![]() ![]() |
Post
#1
|
|
|
Grupa: Zarejestrowani Postów: 872 Pomógł: 94 Dołączył: 31.03.2010 Ostrzeżenie: (0%)
|
Cześć, mam problem z decyzją, czy zastosować kompozycję czy dziedziczenie.
Stan aktualny: MatchInterface (interface) Match (class, implementuje MatchInterface) Chciałbym stworzyć nowy rodzaj Matcha (dopasowania), który zyskuje nową metodę "getName()" oraz argument konstruktora względem klasy Match. W tym celu dodałem nowy interface oraz klasę: NamedMatchInterface (interface dziedziczący po MatchInterface dodający nową metodą getNamed()) NamedMatch (class, implementuje NamedMatchInterface) Proszę nie zwracać uwagi na na nazewnictwo, jest to PSR ale nie wykluczone, że zmienię tę konwencję, bo mi trochę nie odpowiada. Moje pytanie brzmi: klasa "NamedMatch" powinna dziedziczyć po klasie "Match" i dodawać nową metodę oraz nadpisać konstruktor, czy jednak zastosować kompozycję? Z punktu widzenia testów jednostkowych oraz możliwości rozwoju skłaniam się do kompozycji, jednak chciałbym poznać Wasze zdanie. Edit: Niby to powinna być kompozycja, bo dochodzi nowa metoda, jednak 4 inne metody są identyczne jak w klasie Match i w przypadku zastosowania kompozycji będą po prostu proxowane do klasy Match. Ten post edytował lukaskolista 4.12.2016, 14:24:52 |
|
|
|
Post
#2
|
|
|
Grupa: Zarejestrowani Postów: 37 Pomógł: 9 Dołączył: 14.09.2016 Skąd: Śląskie Ostrzeżenie: (0%)
|
Kompozycję stosuje się wtedy, gdy między klasami zachodzi relacja typu „całość ↔ część” tzn. nowa klasa zawiera w sobie istniejącą klasę.
Dziedziczenie stosuje się wtedy, gdy między klasami zachodzi relacja „generalizacja ↔ specjalizacja” tzn. nowa klasa jest szczególnym rodzajem już istniejącej klasy. Myślę, że w twoim przypadku jest dziedziczenie. |
|
|
|
Post
#3
|
|
|
Grupa: Zarejestrowani Postów: 872 Pomógł: 94 Dołączył: 31.03.2010 Ostrzeżenie: (0%)
|
Dokładnie na odwrót - kompozycja. Nowa metoda nie jest specjalizacją klasy, a dodatkową funkcjonalnością.
Poza tym trafiłeś na jedną z licznych zasad prezentowanych na blogach. Klasy Match i NamedMatch są na tym samym poziomie specjalizacji, przy czym NamedMatch ma jedną funkcjonalność więcej, reszta jest wspólna. Ten post edytował lukaskolista 4.12.2016, 15:16:41 |
|
|
|
Post
#4
|
|
|
Grupa: Zarejestrowani Postów: 8 068 Pomógł: 1414 Dołączył: 26.10.2005 Ostrzeżenie: (0%)
|
NamedMatchInterface powinien rozszerzać MatchInterface, a klasy implementować odpowiedni interface.
|
|
|
|
Post
#5
|
|
|
Grupa: Zarejestrowani Postów: 872 Pomógł: 94 Dołączył: 31.03.2010 Ostrzeżenie: (0%)
|
Cytat NamedMatchInterface powinien rozszerzać MatchInterface, a klasy implementować odpowiedni interface. Bez urazy, ale co to ma do tematu? Napisałeś to, co ja napisałem już na samym początku tego wątku. MatchInterface -> Match MatchInterface -> NamedMatchInterface -> NamedMatch Chodzi o to, czy zastosować kompozycję, czy dziedziczenie. Ten post edytował lukaskolista 4.12.2016, 15:29:17 |
|
|
|
Post
#6
|
|
|
Grupa: Zarejestrowani Postów: 8 068 Pomógł: 1414 Dołączył: 26.10.2005 Ostrzeżenie: (0%)
|
Ok spoko. Ja bym zastosował dziedziczenie. Nie warto chyba w tym przypadku komplikować sobie życia kompozycją.
|
|
|
|
Post
#7
|
|
|
Grupa: Zarejestrowani Postów: 37 Pomógł: 9 Dołączył: 14.09.2016 Skąd: Śląskie Ostrzeżenie: (0%)
|
Dokładnie na odwrót - kompozycja. Nowa metoda nie jest specjalizacją klasy, a dodatkową funkcjonalnością. Poza tym trafiłeś na jedną z licznych zasad prezentowanych na blogach. Klasy Match i NamedMatch są na tym samym poziomie specjalizacji, przy czym NamedMatch ma jedną funkcjonalność więcej, reszta jest wspólna. Edit. Zerknąłem do googla i masz rację - jest to kompozycja. Ten post edytował rafkon1990 4.12.2016, 17:57:53 |
|
|
|
Post
#8
|
|
|
Grupa: Zarejestrowani Postów: 872 Pomógł: 94 Dołączył: 31.03.2010 Ostrzeżenie: (0%)
|
Teraz jeszcze zostaje kwestia interfaceow. Czy NamedMatchInterface moze dziedziczyc po MatchInterface, czy jednak powinien specyfikować kontrakt na nowo? Co do tego to nie mam pojecia bo kompozycje rozpatruje się w kontekście implementacji a nie abstrakcji, przynajmniej o abstrakcji nic nie mogę znaleźć.
|
|
|
|
Post
#9
|
|
|
Grupa: Zarejestrowani Postów: 8 068 Pomógł: 1414 Dołączył: 26.10.2005 Ostrzeżenie: (0%)
|
Raczej powinien dziedziczyć, tym bardziej że kontrakt jest taki sam wspólny.
|
|
|
|
Post
#10
|
|
|
Grupa: Zarejestrowani Postów: 872 Pomógł: 94 Dołączył: 31.03.2010 Ostrzeżenie: (0%)
|
Chyba tak jak piszesz interface powinien dziedziczyć, bo opisuje kontrakt, a nie implementację, natomiast implementacja powinna być zrealizowana za pomocą kompozycji.
Tak z ciekawości zapytam: Jak testujecie klasy, które po sobie dziedziczą? Przykładowo mamy klasę A z metodą x() i y() + mamy testy do tej klasy i metody. Do tego mamy klasę B też z metodą x(), która jest odziedziczona z klasy A, natomiast metoda y() jest inna. Jak testujecie klasę B? Piszecie testy dla metody x() w obu klasach? Dodatkowo co w przypadku, gdy klasa potomna korzysta z metody rodzica + dodaje swoją logikę - nie da się zamockować klasy rodzica, bo dziecziczenie to mechaizm języka. |
|
|
|
Post
#11
|
|
|
Grupa: Zarejestrowani Postów: 8 068 Pomógł: 1414 Dołączył: 26.10.2005 Ostrzeżenie: (0%)
|
Normalnie. Testujesz klasę której używasz. Więc jeśli używasz B to testujesz metody których używasz. Ciebie nie interesuje że w B jest tylko zmieniona Y a X jest brana z A, Ciebie interesuje wynik metody. Bo jeśli zmieni się metoda A::X to Twoj kod przestaje działać.
|
|
|
|
Post
#12
|
|
|
Grupa: Zarejestrowani Postów: 1 590 Pomógł: 185 Dołączył: 19.04.2006 Skąd: Gdańsk Ostrzeżenie: (0%)
|
Cytat czy zastosować kompozycję czy dziedziczenie. - pytanie dziwne, bo to dwa przeciwstawne wzorce.I "część wspólna" to nie jest powód, by dziedziczyć czy tym bardziej tworzyć kompozycję. To wg mnie podstawowy błąd. Tak się robiło w XIX wieku, gdzie programy były statyczne i pisane z myślą o tym, że nigdy nie będą zmieniane, W dobie adżajlów używanie wzorców, które bazują na bardzo sztywnej relacji pomiędzy obiektami (jak dziedziczenie) jest sztuką dla sztuki. Dziedziczenie pięknie wygląda tylko w teorii, w praktyce zaraz zmieni się w stertę antywzorców takich jak jojo czy callsuper. Trzeba zawsze dążyć do tego, aby implementacja była jak najprostsza i jak najbardziej skalowalna. Jeśli mamy część wspólną to wystarczy: - utworzyć klasę np. MatchService (część wspólna) - dostarczyć ją do klas Match i NamedMatch (które implementują część wspólną, oraz korzystają z jej funkcjonalności) Czyli prosta fasada. Dzięki temu możemy dowolnie rozwijać każdą klasę nie martwiąc się, że np. złamiemy kontrakt klasy nadrzędnej. Wiele frameworków ma wręcz zautomatyzowane tworzenie fasad, gdzie fasadę wpisuje się w .cfg i już mamy gotowy do użycia obiekt Match lub NamedMatch wraz ze wszystkimi zależnościami. |
|
|
|
Post
#13
|
|
|
Grupa: Zarejestrowani Postów: 872 Pomógł: 94 Dołączył: 31.03.2010 Ostrzeżenie: (0%)
|
Błędnie założyłeś, że te obiekty są usługami. Kompozycja jest przestarzała? Od kiedy?
Zrobiłem to tak: MatchInterface -> Match (class) NamedMatchInterface -> NamedMatch (class) NamedMatchInterface posiada metody: getName(): string getMatch(): MatchInterface Ten post edytował lukaskolista 5.12.2016, 10:47:19 |
|
|
|
Post
#14
|
|
|
Grupa: Zarejestrowani Postów: 3 034 Pomógł: 366 Dołączył: 24.05.2012 Ostrzeżenie: (0%)
|
@offtop
PSR nie definiuje standardu nazewnictwa klas, interfejsów itd (IMG:style_emoticons/default/smile.gif) Wspomniane było o tym kiedyś, ale w kontekście nazewnictwa dla samego PSR, a w projekcie można przyjąć sobie jaki chcesz standard, ja ostatnio preferuje bez suffixów, według mnie tak jest lepiej:
niż:
Bo tak jasno mówisz że to jest obiekt danego typu a nie jakiś interfejs |
|
|
|
Post
#15
|
|
|
Grupa: Zarejestrowani Postów: 8 068 Pomógł: 1414 Dołączył: 26.10.2005 Ostrzeżenie: (0%)
|
Widzisz... I tu jest problem (IMG:style_emoticons/default/smile.gif)
Bo wg. Ciebie oczekujesz Obiektu konkretnego typu. Dodając sufix widzisz że oczekujesz też Typu, ale już widzisz że Obiekt Może być Potter implementujący Interface. Nie mając Sufixu musisz się posiłkować dokumentacją żeby wiedzieć czy to co tam jest to Interface czy konkretny obiekt. A co jeśli nazwiesz Interface Book, a potem chcesz klasę Book? Bo robisz z niej np. dziedziczenie? Interface, Trait, abstract to wszystko powinno być dodawane do nazwy. |
|
|
|
![]() ![]() |
|
Aktualny czas: 20.12.2025 - 21:40 |