Podczas modelowania obiektu za pomocą dzieci często dołącza się dzieci za pomocą kompozycji jako członka klasy nadrzędnej. Czasami jednak dzieci muszą powiedzieć rodzicowi coś, muszą wywołać funkcję rodzica. Jak można to osiągnąć za pomocą C ++? Niektóre opcje to:
Ustaw klasę nadrzędną na globalną, aby obiekty potomne mogły wywoływać funkcje składowe obiektu nadrzędnego.
Wstrzyknij obiekt nadrzędny jako wskaźnik lub odnośnik do każdego obiektu podrzędnego. Następnie, gdy dziecko musi coś powiedzieć obiektowi nadrzędnemu, zawsze może to zrobić, ponieważ ma zmienną składową, której może użyć.
Jakie są inne metody na to? Czy istnieje ogólny wzór lub nazwa tego rodzaju rzeczy?
Zauważ, że interesują mnie pomysły i rozwiązania w C ++, ponieważ szczegóły będą inne w innych językach obiektowych. Na przykład punkt 2 powyżej wspomina o „wskaźnikach lub referencjach” i oba są możliwe tylko w C ++. C ++ ma funkcje językowe, które nie są obecne w innych językach, dlatego implementacje rozwiązania problemu potencjalnie będą zawierać te cechy językowe, dzięki czemu rozwiązanie będzie inne niż to, co ktoś może wymyślić w innym języku.
delegate
wystarczy proste ?Odpowiedzi:
Po pierwsze, może to być zapach kodu. Zastosowanie kompozycji dla rodzica / dzieci polega na tym, że rodzic wie o dzieciach, ale nie odwrotnie. Zwłaszcza jeśli relacja jest bardziej „zawiera” niż „składa się z”.
Odwołanie do elementu nadrzędnego jest możliwe i dość powszechne w C ++. W innych językach częściej używany jest obiekt funkcji lub zdarzenie, aby umożliwić dziecku komunikowanie rzeczy, które osoby z zewnątrz mogą chcieć wiedzieć. Jest to typowy wzorzec typu subskrybent publikujący. Podejrzewam, że to, co jest bardziej idiomatyczne, zależy od używanej wersji C ++ i standardów twojej bazy kodu.
źródło
Jak zauważyli inni, podstawową ideą wstrzykiwania obiektu nadrzędnego jako wskaźnika lub odniesienia jest droga - w zasadzie.
Ma to jedną wadę: cykliczna zależność między rodzicem a dzieckiem. Jeśli chcesz tego uniknąć, zdefiniuj abstrakcyjną klasę bazową (interfejs),
IParent
z której dziedziczy Twój rodzic.IParent
powinien zawierać metody jako funkcje wirtualne, które dziecko chce wywołać. Następnie wstrzyknij rodzic jako odniesienie doIParent
. To znacznie ułatwia testowanie dziecka, ponieważ teraz możesz łatwo zastąpić obiekt nadrzędny obiektem próbnym.Jeśli Twoje dziecko musi wywołać tylko jedną funkcję obiektu nadrzędnego, cała
IParent
klasa może być przewymiarowana. W takim przypadku wystarczy wstrzyknąć wskaźnik do funkcji składowej do dziecka lub obiekt funktora otaczający tę funkcję składową.źródło
To, co możesz zrobić, to zachować odniesienie do rodzica w klasie potomnej według składu. W ten sposób dziecko zna swojego rodzica i może przywoływać na nim publiczne metody.
Więc wybrałbym opcję 2. Musisz jednak zachować ostrożność, gdy dziecko jest usuwane z rodzica, musisz usunąć odniesienie do rodzica w dziecku i wskazać na null (lub nowego rodzica, jeśli ma jeden). Lub możesz po prostu usunąć obiekt potomny, w zależności od kontekstu.
źródło
Przekaż im referencję lub wskaźnik do rodzica. Możesz uczynić ich przyjaciółmi rodzica lub upublicznić wywoływaną metodę. Jeśli nie chcesz wykonać żadnej z powyższych czynności, możesz przekazać im obiekt „pomostowy”, który ujawnia jedną z metod rodzica jako publiczną i sam jest klasą zagnieżdżoną prive, dzięki czemu ma dostęp do każdej metody rodzica ). Jednak w wielu sytuacjach może to być nieco zbyt skomplikowane.
źródło
Jest całkowicie wykonalną opcją. Wszystkie współczesne języki mają funkcję, która może być użyta w odniesieniu do innego języka.
źródło
Istnieje podobne podejście z niewielkimi różnicami, ale daje zalety:
Powiedz, że rodzic A zawiera składnik C.
W komponencie C zadeklaruj interfejs C i przytrzymaj odniesienie do niego. Jest to interfejs komponentu ze światem zewnętrznym.
Element nadrzędny A implementuje interfejs C i ustawia swoje odniesienie w komponencie C. Komponent C postrzega element nadrzędny A jako interfejs C.
Chodzi o to: Komponent mówi na zewnątrz za pomocą swojego interfejsu.
Zalety korzystania z tego nad bezpośrednim ustawianiem elementu nadrzędnego to:
Powiedz, że komponent coś robi i musi powiadomić rodzica. Wywołuje interfejs. Później decydujesz, że chcesz zmienić rodzica. Ten komponent w ogóle się nie przejmuje i nie wprowadzisz w nim żadnych zmian.
Powiedz później, że chcesz powiadomić wiele obiektów o zdarzeniu. Po prostu tworzysz listę InterfaceC i dodajesz do niej odniesienia.
Wady: klasa nadrzędna ostatecznie zaimplementuje wiele interfejsów (myślę o tym jednak jako o przewadze, ponieważ patrząc na deklarację klasy, od razu wiem, kto z nią rozmawia)
źródło
Zauważ, że jest to specyficzne dla c #. Nie wiem, czy c ++ ma coś podobnego.
Jeśli masz formularz GUI z przyciskami, zwykle masz inne podejście, korzystając z subskrypcji zdarzeń, znanej również jako Observer_pattern lub Publish-subscribe pattern .
Przycisk zwykle nie zna konkretnej formy, w której żyje. Zamiast tego przycisk wyzwala lub publikuje zdarzenie, a formularz otrzymuje subskrybowane powiadomienie i może odpowiednio zareagować.
Oprócz wytycznych ten mechanizm może być stosowany w każdej relacji między dzieckiem a dzieckiem
źródło