Szukam dobrego, przejrzystego sposobu obejścia faktu, że PHP5 nadal nie obsługuje wielokrotnego dziedziczenia. Oto hierarchia klas:
Message
- TextMessage
-------- InvitationTextMessage
- EmailMessage
-------- InvitationEmailMessage
Te dwa rodzaje zajęć Invitation * mają ze sobą wiele wspólnego; Chciałbym mieć wspólną klasę rodzicielską, Invitation, po której oboje odziedziczyliby. Niestety mają też wiele wspólnego ze swoimi obecnymi przodkami ... TextMessage i EmailMessage. Klasyczne pragnienie wielokrotnego dziedziczenia tutaj.
Jakie jest najlżejsze podejście do rozwiązania problemu?
Dzięki!
php
oop
inheritance
Alex Weinstein
źródło
źródło
Odpowiedzi:
Alex, w większości przypadków dziedziczenie wielokrotne jest sygnałem, że struktura obiektu jest nieco niepoprawna. W sytuacji, którą opisałeś, widzę, że odpowiedzialność klasowa jest po prostu zbyt szeroka. Jeśli Message jest częścią modelu biznesowego aplikacji, nie powinien zajmować się renderowaniem danych wyjściowych. Zamiast tego możesz podzielić odpowiedzialność i użyć MessageDispatcher, który wysyła wiadomość przekazaną za pomocą zaplecza tekstowego lub html. Nie znam twojego kodu, ale pozwól mi to zasymulować w ten sposób:
W ten sposób możesz dodać specjalizację do klasy Message:
Zauważ, że MessageDispatcher podejmie decyzję, czy wysłać jako HTML, czy zwykły tekst, w zależności od
type
właściwości przekazanej w obiekcie Message.Podsumowując, odpowiedzialność podzielona jest na dwie klasy. Konfiguracja wiadomości odbywa się w klasie InvitationHTMLMessage / InvitationTextMessage, a algorytm wysyłania jest delegowany do dyspozytora. Nazywa się to wzorcem strategii, więcej na ten temat możesz przeczytać tutaj .
źródło
Tracing
(to tylko przykład), w której chcesz mieć ogólne rzeczy, takie jak debugowanie w pliku, wysyłanie wiadomości SMS w przypadku krytycznego problemu i tak dalej. Wszystkie twoje klasy są dziećmi tej klasy. Teraz przypuśćmy, że chcesz utworzyć klasę,Exception
która powinna mieć te funkcje (= dzieckoTracing
). Ta klasa musi być dzieckiemException
. Jak projektujesz takie rzeczy bez wielokrotnego dziedziczenia? Tak, zawsze możesz mieć rozwiązanie, ale zawsze będziesz blisko włamania. A hakowanie = drogie rozwiązanie na dłuższą metę. Koniec opowieści.Może możesz zastąpić relację „jest-jest” relacją „ma-a”? Zaproszenie może zawierać wiadomość, ale niekoniecznie musi to być wiadomość „jest”. Może zostać potwierdzone np. Zaproszenie, co nie pasuje do modelu Message.
Wyszukaj „skład a dziedziczenie”, jeśli chcesz dowiedzieć się więcej na ten temat.
źródło
Jeśli mogę zacytować Phila w tym wątku ...
I Chris ....
Myślałem, że obaj mają przydatne linki. Nie mogę się doczekać, aby wypróbować cechy, a może niektóre mieszanki ...
źródło
Framework Symfony ma do tego wtyczkę mixin , możesz chcieć to sprawdzić - nawet dla pomysłów, jeśli nie chcesz go używać.
Odpowiedzią na „wzorzec projektowy” jest wyodrębnienie współdzielonej funkcjonalności w osobnym komponencie i komponowanie w czasie wykonywania. Pomyśl o sposobie wyodrębnienia funkcji Invitation jako klasy, która zostanie powiązana z Twoimi klasami Message w inny sposób niż dziedziczenie.
źródło
Używam cech w PHP 5.4 jako sposobu rozwiązania tego problemu. http://php.net/manual/en/language.oop5.traits.php
Pozwala to na klasyczne dziedziczenie z rozszerzeniami, ale także daje możliwość umieszczenia wspólnych funkcjonalności i właściwości w „cesze”. Jak mówi instrukcja:
źródło
Wygląda na to, że wzór dekoratora może być odpowiedni, ale trudno to stwierdzić bez dodatkowych szczegółów.
źródło
To jest zarówno pytanie, jak i rozwiązanie ...
A co z magicznym _ wywołaniem (),metody _get (), __set ()? Nie testowałem jeszcze tego rozwiązania, ale co jeśli utworzysz klasę multiInherit. Chroniona zmienna w klasie potomnej może zawierać tablicę klas do dziedziczenia. Konstruktor w klasie z wieloma interfejsami mógłby tworzyć wystąpienia każdej dziedziczonej klasy i łączyć je z własnością prywatną, np. _Ext. Metoda __call () może użyć funkcji method_exists () na każdej z klas w tablicy _ext, aby zlokalizować poprawną metodę do wywołania. __get () i __set mogą zostać użyte do zlokalizowania właściwości wewnętrznych lub jeśli jesteś ekspertem z referencjami, możesz sprawić, że właściwości klasy potomnej i klas dziedziczonych będą odwołaniami do tych samych danych. Wielokrotne dziedziczenie obiektu byłoby niewidoczne dla kodu używającego tych obiektów. Również, obiekty wewnętrzne mogą w razie potrzeby uzyskiwać bezpośredni dostęp do dziedziczonych obiektów, o ile tablica _ext jest indeksowana według nazwy klasy. Wyobraziłem sobie stworzenie tej superklasy i jeszcze jej nie zaimplementowałem, ponieważ uważam, że jeśli to zadziała, może to doprowadzić do rozwoju różnych złych nawyków programistycznych.
źródło
instanceof
)Mam kilka pytań, które pozwolą Ci wyjaśnić, co robisz:
1) Czy obiekt wiadomość prostu zawierać np treść wiadomości, odbiorcę, TERMINARZ? 2) Co zamierzasz zrobić z obiektem zaproszenia? Czy trzeba go traktować specjalnie w porównaniu z wiadomością e-mail? 3) Jeśli tak, CO jest w tym takiego specjalnego? 4) Jeśli tak, to dlaczego typy wiadomości wymagają odmiennej obsługi w przypadku zaproszenia? 5) A co jeśli chcesz wysłać wiadomość powitalną lub wiadomość OK? Czy to też nowe obiekty?
Wygląda na to, że próbujesz połączyć zbyt wiele funkcji w zestaw obiektów, które powinny zajmować się tylko przechowywaniem treści wiadomości - a nie tym, jak należy z nią postępować. Jak dla mnie widzisz, nie ma różnicy między zaproszeniem a zwykłą wiadomością. Jeśli zaproszenie wymaga specjalnej obsługi, oznacza to logikę aplikacji, a nie typ wiadomości.
Na przykład: system, który zbudowałem, miał współdzielony podstawowy obiekt wiadomości, który został rozszerzony na SMS, e-mail i inne typy wiadomości. Jednak: nie były one dalej przedłużane - wiadomość z zaproszeniem była po prostu wstępnie zdefiniowanym tekstem, który miał być wysłany za pośrednictwem wiadomości typu E-mail. Konkretny wniosek o zaproszenie dotyczyłby walidacji i innych wymagań dotyczących zaproszenia. W końcu wszystko, co chcesz zrobić, to wysłać wiadomość X do odbiorcy Y, który powinien być systemem dyskretnym sam w sobie.
źródło
Ten sam problem co Java. Spróbuj użyć interfejsów z funkcjami abstrakcyjnymi do rozwiązania tego problemu
źródło
PHP obsługuje interfejsy. To może być dobry zakład, w zależności od Twoich zastosowań.
źródło
A co z klasą Invitation znajdującą się bezpośrednio pod klasą Message?
więc hierarchia idzie:
Wiadomość
--- Zaproszenie
------ Wiadomość tekstowa
------ Wiadomość e-mail
W klasie Invitation dodaj funkcjonalność, która była w InvitationTextMessage i InvitationEmailMessage.
Wiem, że zaproszenie nie jest tak naprawdę typem wiadomości, to bardziej funkcjonalność wiadomości. Więc nie jestem pewien, czy to dobry projekt OO, czy nie.
źródło