Zastanawiam się, co jest lepsze pod względem dobrego projektowania OOP, czystego kodu, elastyczności i unikania zapachów kodu w przyszłości. Sytuacja obrazowa, w której masz wiele bardzo podobnych obiektów, które musisz reprezentować jako klasy. Klasy te nie mają żadnej konkretnej funkcjonalności, tylko klasy danych i różnią się tylko nazwą (i kontekstem) Przykład:
Class A
{
String name;
string description;
}
Class B
{
String name;
String count;
String description;
}
Class C
{
String name;
String count;
String description;
String imageUrl;
}
Class D
{
String name;
String count;
}
Class E
{
String name;
String count;
String imageUrl;
String age;
}
Czy lepiej byłoby przechowywać je w osobnych klasach, aby uzyskać „lepszą” czytelność, ale przy wielu powtórzeniach kodu, czy lepiej byłoby zastosować dziedziczenie, aby uzyskać większą SUSZENIE?
Używając dziedziczenia, uzyskasz coś takiego, ale nazwy klas utracą znaczenie kontekstowe (z powodu a-a, a nie-a):
Class A
{
String name;
String description;
}
Class B : A
{
String count;
}
Class C : B
{
String imageUrl;
}
Class D : C
{
String age;
}
Wiem, że dziedziczenie nie jest i nie powinno być używane do ponownego użycia kodu, ale nie widzę żadnego innego możliwego sposobu na ograniczenie powtarzania kodu w takim przypadku.
źródło
Dokładnie. Spójrz na to poza kontekstem:
Jakie właściwości ma litera D? Pamiętasz? Co się stanie, jeśli jeszcze bardziej skomplikujesz hierarchię:
A co jeśli horror po horrorze chcesz dodać pole imageUrl do F, ale nie do E? Nie możesz wyprowadzić go z C i E.
Widziałem rzeczywistą sytuację, w której wiele różnych typów komponentów miało nazwę, identyfikator i opis. Ale nie było to z natury ich składników, to był tylko zbieg okoliczności. Każdy z nich miał identyfikator, ponieważ były przechowywane w bazie danych. Nazwa i opis były do wyświetlenia.
Produkty miały również identyfikator, nazwę i opis z podobnych powodów. Ale to nie były komponenty, ani też komponenty. Nigdy nie zobaczyłbyś tych dwóch rzeczy razem.
Ale jakiś programista przeczytał o DRY i zdecydował, że usunie wszelkie ślady duplikacji z kodu. Nazwał więc wszystko produktem i zrezygnował z konieczności definiowania tych pól. Zostały one zdefiniowane w produkcie i wszystko, co wymagało tych pól, mogło pochodzić z produktu.
Nie mogę powiedzieć wystarczająco mocno: To nie jest dobry pomysł.
DRY nie polega na usuwaniu potrzeby posiadania wspólnych właściwości. Jeśli obiekt nie jest Produktem, nie nazywaj go Produktem. Jeśli Produkt nie WYMAGA Opisu, ze względu na jego charakter jest nim, nie definiuj Opisu jako Własności Produktu.
W końcu zdarzyło się, że mieliśmy Komponenty bez opisów. Zaczęliśmy więc mieć puste opisy w tych obiektach. Nie ma wartości zerowej. Zero. Zawsze. Dla każdego produktu typu X ... lub później Y ... i N.
Jest to rażące naruszenie zasady substytucji Liskowa.
DRY polega na tym, aby nigdy nie stawić się w sytuacji, w której możesz naprawić błąd w jednym miejscu i zapomnieć o zrobieniu tego gdzie indziej. Tak się nie stanie, ponieważ masz dwa obiekty o tej samej właściwości. Nigdy. Więc nie martw się o to.
Jeśli kontekst klas pokazuje, że powinieneś, co będzie bardzo rzadkie, wtedy i tylko wtedy powinieneś rozważyć wspólną klasę nadrzędną. Ale jeśli są to właściwości, zastanów się, dlaczego nie używasz interfejsu.
źródło
Dziedziczenie jest sposobem na osiągnięcie zachowania polimorficznego. Jeśli twoje klasy nie zachowują się, dziedziczenie jest bezużyteczne. W tym przypadku nie wziąłbym nawet pod uwagę obiektów / klas, lecz struktury.
Jeśli chcesz mieć możliwość umieszczania różnych struktur w różnych częściach swojego zachowania, rozważ interfejsy z metodami lub właściwościami get / set, takimi jak IHasName, IHasAge itp. Dzięki temu projekt będzie znacznie czystszy i pozwoli na lepsze ich zestawienie rodzaj hierarchii.
źródło
Czy nie do tego służą interfejsy? Niepowiązane klasy o różnych funkcjach, ale o podobnej właściwości.
źródło
Twoje pytanie wydaje się być sformułowane w kontekście języka, który nie obsługuje wielokrotnego dziedziczenia, ale nie określa tego konkretnie. Jeśli pracujesz w języku, który obsługuje wielokrotne dziedziczenie, staje się to trywialnie łatwe do rozwiązania z tylko jednym poziomem dziedziczenia.
Oto przykład, jak można to rozwiązać za pomocą wielokrotnego dziedziczenia.
źródło