Załóżmy, że masz:
+--------+ +------+
| Animal | | Food |
+-+------+ +----+-+
^ ^
| |
| |
+------+ +-------+
| Deer | | Grass |
+------+ +-------+
Deer
dziedziczy Animal
i Grass
dziedziczy po Food
.
Jak na razie dobrze. Animal
przedmioty mogą jeść Food
przedmioty.
Teraz pomieszajmy to trochę. Pozwala dodać, Lion
który dziedziczy Animal
.
+--------+ +------+
| Animal | | Food |
+-+-----++ +----+-+
^ ^ ^
| | |
| | |
+------+ +------+ +-------+
| Deer | | Lion | | Grass |
+------+ +------+ +-------+
Teraz mamy problem, ponieważ Lion
możemy jeść zarówno Deer
i Grass
, ale Deer
tak nie Food
jest Animal
.
Bez korzystania z wielokrotnego dziedziczenia i projektowania obiektowego, jak rozwiązać ten problem?
FYI: Użyłem http://www.asciiflow.com, aby stworzyć diagramy ASCII.
object-oriented
object-oriented-design
Michael Irey
źródło
źródło
IHuntable
, Sheep and Cow sąIHerdable
(kontrolowane przez człowieka), a Lion implementuje tylko IAnimal, co nie implikuje żadnego z tych interfejsów. AOE3 obsługuje sprawdzanie zestawu interfejsów obsługiwanych przez konkretny obiekt (podobny doinstanceof
), który pozwala programowi sprawdzać jego możliwości.Odpowiedzi:
Relacje IS A = Dziedziczenie
Lew jest zwierzęciem
MA Powiązania = Skład
Samochód ma koło
MOŻNA zrobić relacje = interfejsy
Mogę jeść
źródło
ICanBeEaten
lubIEdible
OO to tylko metafora wzorująca się na prawdziwym świecie. Ale metafory idą tylko tak daleko.
Zwykle nie ma właściwego sposobu na modelowanie czegoś w OO. Jest właściwy sposób, aby to zrobić dla konkretnego problemu w określonej domenie i nie powinieneś oczekiwać, że zadziała dobrze, jeśli zmienisz swój problem, nawet jeśli obiekty domeny są takie same.
Myślę, że jest to częste nieporozumienia większości Comp. Inż. studenci mają w pierwszych latach. OO nie jest uniwersalnym rozwiązaniem, tylko porządnym narzędziem do rozwiązywania problemów, które mogą odpowiednio modelować domenę.
Nie odpowiedziałem na pytanie, właśnie dlatego, że brakuje nam informacji o domenie. Mając powyższe na uwadze, możesz być w stanie zaprojektować coś, co odpowiada Twoim potrzebom.
źródło
Chcesz dalej dzielić zwierzęta na ich podklasy (lub przynajmniej o ile ma to sens w tym, co robisz). Biorąc pod uwagę, że pracujesz z czymś, co wygląda jak podstawowe zwierzęta i dwa rodzaje pożywienia (rośliny i mięso), sensowne jest użycie zwierząt mięsożernych i roślinożernych do dalszego zdefiniowania zwierzęcia i utrzymania go w oddzielności. Oto, co dla ciebie przygotowałem.
Jak widać, oboje ujawniają metodę jedzenia, ale to, co jedzą, zmienia się. Lew może teraz zabijać jelenia, jeleń może umrzeć i zwrócić DeerMeat, a pierwotne pytanie PO, jak pozwolić lwie jeść jelenia, ale bez trawy jest odpowiedzią bez opracowania całego ekosystemu.
Oczywiście staje się to interesujące bardzo szybko, ponieważ Jeleń można również uznać za rodzaj mięsa, ale dla uproszczenia stworzyłbym metodę zwaną kill () pod jeleniem, która zwraca mięso jelenia, i umieściłem to jako klasa betonu rozciągającego mięso.
źródło
Eat(Plant p)
iEat(Meat m)
oba naruszają LSP.Mój projekt wyglądałby tak:
Ponieważ Zwierzęta wdrażają IMeat, a Jeleń jest Zwierzęciem (Roślinożernym), Lewem, który jest Zwierzęciem (Carnivore), który może jeść IMeat może również jeść Jelenia.
Jeleń jest roślinożercą, więc może jeść trawę, ponieważ wprowadza IVegetable.
Zwierzęta mięsożerne nie mogą jeść IVegeable, a zwierzęta roślinożerne nie mogą jeść IMeat.
źródło
To, co zwierzę może zjeść, w rzeczywistości nie tworzy hierarchii, w tym przypadku natura niewybaczalnie nie dostosowała się do prostego modelowania obiektowego (zauważ, że nawet gdyby tak było, zwierzę musiałoby odziedziczyć po jedzeniu, ponieważ jest pokarmem).
Wiedza o tym, jakie pokarmy może jeść zwierzę, nie może żyć całkowicie z żadną z tych klas, więc samo odniesienie do jakiegoś członka hierarchii żywieniowej nie wystarczy, aby powiedzieć ci, co możesz jeść.
To relacja wiele do wielu. Oznacza to, że za każdym razem, gdy dodajesz zwierzę, musisz dowiedzieć się, co ono może zjeść, i za każdym razem, gdy dodajesz jedzenie, musisz dowiedzieć się, co może je zjeść. To, czy będzie można wykorzystać dalszą strukturę, zależy od tego, jakie zwierzęta i pokarm modelujesz.
Wielokrotne dziedziczenie też tak naprawdę nie rozwiązuje zbyt dobrze. Potrzebujesz jakiejś kolekcji rzeczy, które zwierzę może jeść, lub zwierząt, które mogą jeść.
źródło
Podejdę do problemu z innej strony: OOP dotyczy zachowania. Czy w twoim przypadku zachowuje
Grass
się jakieś dzieckoFood
? Więc w twoim przypadku nie będzieGrass
klasy, a przynajmniej nie zostanie ona odziedziczonaFood
. Ponadto, jeśli musisz wymusić, kto może jeść, co w czasie kompilacji, wątpliwe jest, czy potrzebujeszAnimal
abstrakcji. Nie jest też rzadkością, że mięsożercy jedzą trawę , choć nie pożywienia.Zaprojektowałbym to jako (nie zawracając sobie głowy sztuką ASCI):
IEdible
z właściwościąType
, która jest wyliczeniem mięsa, roślin, tuszy itp. (nie zmienia się to często i nie ma żadnego konkretnego zachowania, dlatego nie ma potrzeby modelowania tego jako hierarchii klas).Animal
metodamiCanEat(IEdible food)
iEat(IEdible food)
, które są logiczne. Następnie określone zwierzęta mogą sprawdzać, ilekroć mogą w danym przypadku jeść określone pokarmy, a następnie je jeść, aby uzyskać pożywienie / zrobić coś innego. Ponadto modelowałbym klasy Carnivore, Herbivore, Omnivore jako wzór strategii , niż jako część hierarchii zwierząt.źródło
TL; DR: Projekt lub model z kontekstem.
Myślę, że twoje pytanie jest trudne, ponieważ brakuje kontekstu rzeczywistego problemu, który próbujesz rozwiązać. Masz pewne modele i pewne relacje, ale brakuje ci ram, w których musi działać. Bez kontekstu modelowanie i metafory nie działają dobrze, pozostawiając drzwi otwarte na wiele interpretacji.
Myślę, że bardziej produktywne jest skupienie się na sposobie wykorzystania danych. Gdy masz już wzorzec wykorzystania danych, łatwiej jest pracować wstecz do tego, jakie powinny być modele i relacje.
Na przykład bardziej szczegółowe wymagania będą wymagać różnych relacji między obiektami:
Animals
eat
ing nieprzestrzeganiaFood
odczuwalnaGastroliths
Chocolate
jakPoison
dlaDogs
, ale nie dlaHumans
Jeśli zaczniemy od ćwiczenia modelowania prostej przedstawionej relacji, interfejs żywnościowy może być najlepszy; a jeśli jest to suma, w jaki sposób relacje w systemie, to twoja kara. Jednak tylko kilka dodatkowych wymagań lub relacji może znacznie wpłynąć na modele i relacje, które działały w prostszym przypadku.
źródło
Podejście ECS polegające na nadpisywaniu składu:
Pseudo kod:
Nature
tosystem
pętla przechodząca przez te jednostki, szukająca składników, które mają dzięki uogólnionej funkcji zapytania.Nature
spowoduje, że istoty z głodem mięsa zaatakują inne istoty, które mają mięso jako żywność za pomocą swojej broni, chyba że mają do tego bytu powinowactwo. Jeśli atak się powiedzie, istota żywi się swoją ofiarą, po czym ofiara zamieni się w zwłoki pozbawione mięsa.Nature
spowoduje, że istoty z głodem roślin będą się odżywiać istotami, które mają rośliny jako żywność, pod warunkiem, że istnieją.Być może chcemy rozszerzyć
Grass
się na potrzebę światła słonecznego i wody i chcemy wprowadzić światło słoneczne i wodę do naszego świata. NieGrass
mogą jednak szukać ich bezpośrednio, ponieważ tak nie jestmobility
.Animals
mogą również potrzebować wody, ale mogą ją aktywnie szukać, ponieważ mająmobility
. Rozszerzanie i zmienianie tego modelu jest dość łatwe bez kaskadowego niszczenia całego projektu, ponieważ dodajemy nowe komponenty i rozszerzamy zachowanie naszych systemów (lub liczby systemów).źródło
Jak większość rzeczy, to zależy .
To zależy od tego , jak widzisz „ten problem”.
Jeśli pytasz o ogólny problem z implementacją, odpowiedź będzie zależeć od możliwości twojego środowiska. Interfejsy IFood i IAnimal mogą działać, z podklasą EdibleAnimal implementującą oba interfejsy. Jeśli twoje środowisko nie obsługuje interfejsów, po prostu spraw, aby Animal dziedziczyło z żywności.
Jeśli pytasz o ten konkretny problem projektowy, po prostu spraw, że Animal odziedziczy po żywności. To najprostsza rzecz, która może działać.
Jeśli pytasz o te koncepcje projektowe, odpowiedź silnie zależy od tego, co zamierzasz zrobić z modelem. Jeśli jest to gra wideo z psem-jedzącym-psem, a nawet aplikacja do śledzenia harmonogramów karmienia w zoo, może wystarczyć. Jeśli chodzi o koncepcyjny model wzorców zachowań zwierząt, to prawdopodobnie jest trochę płytki.
źródło
Dziedziczenia należy używać do czegoś, co zawsze jest czymś innym i nie może się zmienić. Trawa nie zawsze jest pożywieniem. Na przykład nie jem trawy.
Trawa odgrywa rolę pokarmu dla niektórych zwierząt.
źródło
Właśnie natrafiłeś na podstawowe ograniczenie OO.
OO działa dobrze z hierarchicznymi strukturami. Ale kiedy odejdziesz od ścisłych hierarchii, abstrakcja nie działa tak dobrze.
Wiem wszystko o kompozycjach metamorfozy itp., Które są używane do ominięcia tych ograniczeń, ale są niezdarne i, co ważniejsze, prowadzą do niejasnego i trudnego do naśladowania kodu.
Relacyjne bazy danych zostały wymyślone przede wszystkim w celu uniknięcia ograniczeń ścisłych struktur hierarchicznych.
Na przykład trawa może być również materiałem budowlanym, surowcem do papieru, materiałem na odzież, chwastem lub rośliną uprawną.
Jeleń może być zwierzęciem, żywym inwentarzem, zwierzęciem z zoo lub gatunkiem chronionym.
Lew może być także zwierzęciem z zoo lub gatunkiem chronionym.
Życie nie jest proste.
źródło
Jaki problem? Co robi ten system? Dopóki nie odpowiesz na to pytanie, nie mam pojęcia, jakie klasy mogą być wymagane. Czy próbujesz modelować ekologię za pomocą mięsożerców, roślinożerców i roślin, projektując populacje gatunków w przyszłość? Czy chcesz, aby komputer grał 20 pytań?
Rozpoczynanie projektowania jest stratą czasu, zanim zdefiniowane zostaną przypadki użycia. Widziałem to doprowadzone do absurdalnej skrajności, gdy około dziesięcioosobowy zespół zaczął produkować model OO linii lotniczej za pomocą oprogramowania poprzez zdjęcia. Pracowali przez dwa lata modelując, nie biorąc pod uwagę faktycznych problemów biznesowych. Wreszcie klient zmęczył się czekaniem i poprosił zespół o rozwiązanie rzeczywistego problemu. Całe to modelowanie było całkowicie bezużyteczne.
źródło