Angenommen, Sie haben Folgendes:
+--------+ +------+
| Animal | | Food |
+-+------+ +----+-+
^ ^
| |
| |
+------+ +-------+
| Deer | | Grass |
+------+ +-------+
Deer
erbt von Animal
und Grass
erbt von Food
.
So weit, ist es gut. Animal
Objekte können Food
Objekte essen .
Jetzt mischen wir es ein bisschen durch. Fügen wir ein hinzu, von Lion
dem erbt Animal
.
+--------+ +------+
| Animal | | Food |
+-+-----++ +----+-+
^ ^ ^
| | |
| | |
+------+ +------+ +-------+
| Deer | | Lion | | Grass |
+------+ +------+ +-------+
Jetzt haben wir ein Problem, weil wir Lion
beides essen können Deer
und Grass
, aber es Deer
ist nicht Food
so Animal
.
Wie können Sie dieses Problem lösen, ohne Mehrfachvererbung und objektorientiertes Design zu verwenden?
Zu Ihrer Information: Ich habe http://www.asciiflow.com verwendet , um die ASCII-Diagramme zu erstellen.
object-oriented
object-oriented-design
Michael Irey
quelle
quelle
IHuntable
, Sheep and Cow sindIHerdable
(von Menschen kontrollierbar), und Lion implementiert nur IAnimal, was keine dieser Schnittstellen impliziert. AOE3 unterstützt die Abfrage der Schnittstellen, die von einem bestimmten Objekt (ähnlich wieinstanceof
) unterstützt werden, wodurch ein Programm seine Funktionen abfragen kann.Antworten:
Ist eine Beziehung = Vererbung
Löwe ist ein Tier
Hat eine Beziehung = Zusammensetzung
Auto hat ein Rad
CAN-DO-Beziehungen = Schnittstellen
Ich kann essen
quelle
ICanBeEaten
oderIEdible
OO ist nur eine Metapher, die sich an die reale Welt anlehnt. Aber Metaphern gehen nur so weit.
Normalerweise gibt es keinen richtigen Weg, um etwas in OO zu modellieren. Es gibt einen richtigen Weg, dies für ein bestimmtes Problem in einer bestimmten Domäne zu tun, und Sie sollten nicht erwarten, dass es gut funktioniert, wenn Sie Ihr Problem ändern, auch wenn die Domänenobjekte gleich sind.
Ich denke, dies ist ein häufiges Missverständnis der meisten Comp. Eng. Studenten haben in ihren ersten Jahren. OO ist keine universelle Lösung, sondern nur ein anständiges Tool für einige Probleme, mit denen Ihre Domain einigermaßen gut modelliert werden kann.
Ich habe die Frage nicht beantwortet, weil uns Domain-Informationen fehlen. Vor diesem Hintergrund können Sie jedoch möglicherweise etwas entwerfen, das Ihren Anforderungen entspricht.
quelle
Sie möchten die Tiere weiter in ihre Unterklassen aufteilen (oder zumindest, soweit dies für Ihre Tätigkeit sinnvoll ist). Da Sie mit Tieren und zwei Arten von Lebensmitteln (Pflanzen und Fleisch) arbeiten, ist es sinnvoll, Fleischfresser und Pflanzenfresser zu verwenden, um ein Tier genauer zu definieren und getrennt zu halten. Folgendes habe ich für Sie entworfen.
Wie Sie sehen können, legen beide eine Eat-Methode offen, aber was sie essen, ändert sich. Der Löwe kann jetzt einen Hirsch töten, der Hirsch kann sterben und DeerMeat zurückgeben, und die ursprüngliche Frage, wie ein Löwe einen Hirsch, aber kein Gras fressen darf, wird beantwortet, ohne ein gesamtes Ökosystem zu konstruieren.
Natürlich wird dies sehr schnell interessant, da ein Hirsch auch als Fleischsorte angesehen werden kann. Um die Dinge einfach zu halten, würde ich eine Methode namens kill () unter deer erstellen, die ein Hirschfleisch zurückgibt, und das als a setzen Betonklasse erweitern Fleisch.
quelle
Eat(Plant p)
undEat(Meat m)
beide verletzen LSP.Mein Design würde so aussehen:
Da Tiere IMeat implementieren und Hirsche ein (Pflanzenfresser-) Tier sind, kann Löwe, ein (Fleischfresser-) Tier, das IMeat fressen kann, auch Hirsche fressen.
Hirsche sind Pflanzenfresser, deshalb kann sie Gras fressen, weil sie pflanzlich sind.
Fleischfresser können kein Gemüse essen und Pflanzenfresser können kein Fleisch essen.
quelle
Welches Futter ein Tier essen kann, bildet eigentlich keine Hierarchie. In diesem Fall ist die Natur unentschuldbar gegen eine einfache objektorientierte Modellierung verstoßen.
Das Wissen darüber, welche Lebensmittel ein Tier essen kann, kann mit keiner der Klassen vollständig vereinbar sein. Daher kann es nicht ausreichen, sich nur auf ein Mitglied der Lebensmittelhierarchie zu beziehen, um zu sagen, welche Dinge Sie essen können.
Es ist eine Beziehung von vielen zu vielen. Dies bedeutet, jedes Mal, wenn Sie ein Tier hinzufügen, müssen Sie herausfinden, was es fressen kann, und jedes Mal, wenn Sie ein Futter hinzufügen, müssen Sie herausfinden, was es fressen kann. Ob es eine weitere Struktur gibt, die genutzt werden kann, hängt davon ab, welche Tiere und Lebensmittel Sie modellieren.
Mehrfachvererbung löst dies auch nicht wirklich gut. Sie brauchen eine Art Sammlung von Dingen, die ein Tier essen kann, oder von Tieren, die ein Lebensmittel essen können.
quelle
Ich werde das Problem von einer anderen Seite angehen: Bei OOP geht es um Verhalten. Müssen Sie in Ihrem Fall
Grass
ein Kind seinFood
? In deinem Fall wird es also keineGrass
Klasse geben, oder zumindest wird es nicht von ihr geerbtFood
. Auch wenn Sie erzwingen müssen, wer was zur Kompilierungszeit essen kann, ist es fraglich, ob Sie eineAnimal
Abstraktion benötigen . Es kommt auch nicht selten vor, dass Fleischfresser Gras fressen , wenn auch nicht für den Unterhalt.Also würde ich dies so gestalten (ohne mich mit ASCI-Kunst zu beschäftigen):
IEdible
mit EigenschaftType
, die enum aus Fleisch, Pflanzen, Kadavern usw. besteht (dies ändert sich nicht oft und weist kein spezifisches Verhalten auf, daher ist es nicht erforderlich, dies als Klasse hiearchy zu modellieren).Animal
mit MethodenCanEat(IEdible food)
undEat(IEdible food)
, die logisch sind. Dann können bestimmte Tiere überprüfen, wann immer sie unter bestimmten Umständen Nahrung zu sich nehmen können, und dann diese Nahrung zu sich nehmen, um sich zu ernähren oder etwas anderes zu tun. Außerdem würde ich die Klassen Carnivore, Herbivore, Omnivore als Strategiemuster modellieren , als Teil der Tierhierarchie.quelle
TL; DR: Entwurf oder Modell mit einem Kontext.
Ich denke, Ihre Frage ist schwierig, weil es keinen Zusammenhang mit dem eigentlichen Problem gibt, das Sie zu lösen versuchen. Sie haben einige Modelle und Beziehungen, aber es fehlt der Rahmen, in dem es funktionieren muss. Ohne Kontext funktionieren Modellierung und Metaphern nicht gut, sodass mehrere Interpretationen möglich sind.
Ich halte es für produktiver, sich darauf zu konzentrieren, wie die Daten verarbeitet werden. Sobald Sie das Muster der Datennutzung kennen, können Sie einfacher auf die Modelle und Beziehungen zurückgreifen.
Beispielsweise erfordern detailliertere Anforderungen unterschiedliche Objektbeziehungen:
Animals
eat
nichtFood
mögenGastroliths
Chocolate
wiePoison
fürDogs
, aber nicht fürHumans
Wenn wir mit der Modellierung der dargestellten einfachen Beziehung beginnen, ist das Food Interface möglicherweise das beste. und wenn das die Gesamtsumme ist, wie die Verhältnisse im System dann deine Geldstrafe. Nur ein paar zusätzliche Anforderungen oder Beziehungen können sich jedoch erheblich auf die Modelle und Beziehungen auswirken, die im einfacheren Fall funktionierten.
quelle
ECS-Ansatz "Zusammensetzung über Vererbung":
Pseudocode:
Nature
ist eine Funktionsystem
, die diese Entitäten durchläuft und über eine verallgemeinerte Abfragefunktion nach ihren Komponenten sucht.Nature
Entitäten mit Hunger nach Fleisch werden andere Entitäten angreifen, die Fleisch als Nahrung mit ihren Waffen haben, es sei denn, sie haben eine Affinität zu dieser Entität. Wenn der Angriff erfolgreich ist, ernährt sich die Entität von ihrem Opfer. An diesem Punkt verwandelt sich das Opfer in einen fleischlosen Leichnam.Nature
Entitäten mit Hunger nach Pflanzen werden sich von Entitäten ernähren, die Pflanzen als Nahrung haben, sofern sie existieren.Vielleicht wollen wir das
Grass
Bedürfnis nach Sonnenlicht und Wasser erweitern, und wir wollen Sonnenlicht und Wasser in unsere Welt einführen. IchGrass
kann sie jedoch nicht direkt suchen, wie es nicht der Fall istmobility
.Animals
Vielleicht brauchen sie auch Wasser, können es aber aktiv suchen, seit sie es habenmobility
. Es ist ziemlich einfach, dieses Modell zu erweitern und zu ändern, ohne das gesamte Design zu beschädigen, da wir einfach neue Komponenten hinzufügen und das Verhalten unserer Systeme (oder die Anzahl der Systeme) erweitern.quelle
Wie bei den meisten Dingen kommt es darauf an .
Es hängt davon ab, was Sie unter "diesem Problem" verstehen.
Wenn Sie nach dem allgemeinen Implementierungsproblem fragen, hängt die Antwort von den Fähigkeiten Ihrer Umgebung ab. IFood- und IAnimal-Schnittstellen könnten funktionieren, wobei eine EdibleAnimal-Unterklasse beide Schnittstellen implementiert. Wenn Ihre Umgebung keine Schnittstellen unterstützt, lassen Sie Animal einfach von Food erben.
Wenn Sie nach diesem speziellen Designproblem fragen, lassen Sie Animal einfach von Food erben. Es ist die einfachste Sache, die möglicherweise funktionieren könnte.
Wenn Sie nach diesen Konstruktionskonzepten fragen, hängt die Antwort stark davon ab, was Sie mit dem Modell tun möchten. Wenn es sich um ein Hund-fress-Hund-Videospiel handelt oder um eine Anwendung, mit der Fütterungspläne in einem Zoo verfolgt werden können, reicht es möglicherweise aus, um zu arbeiten. Wenn es sich um ein konzeptionelles Modell für Verhaltensmuster von Tieren handelt, ist es wahrscheinlich ein bisschen oberflächlich.
quelle
Vererbung sollte für etwas verwendet werden, das immer etwas anderes ist und sich nicht ändern kann. Gras ist nicht immer Nahrung. Zum Beispiel esse ich kein Gras.
Gras spielt für bestimmte Tiere die Rolle eines Nahrungsmittels.
quelle
Sie sind gerade auf die grundlegende Einschränkung von OO gestoßen.
OO funktioniert gut mit hierarchischen Strukturen. Aber wenn Sie einmal strengen Hierarchien entkommen, funktioniert die Abstraktion nicht mehr so gut.
Ich weiß alles über Metamorphose-Kompositionen usw., die verwendet werden, um diese Einschränkungen zu umgehen, aber sie sind ungeschickt und führen, was noch wichtiger ist, zu undurchsichtigem und schwer zu verfolgendem Code.
Relationale Datenbanken wurden in erster Linie erfunden, um den Beschränkungen strenger hierarchischer Strukturen zu entkommen.
Zum Beispiel könnte Gras auch ein Baumaterial, ein Rohstoff für Papier, ein Bekleidungsmaterial, ein Unkraut oder eine Ernte sein.
Ein Hirsch kann ein Haustier, ein Vieh, ein Zootier oder eine geschützte Art sein.
Ein Löwe kann auch ein Zootier oder eine geschützte Art sein.
Das Leben ist nicht einfach.
quelle
Welches Problem? Was macht dieses System?Bis Sie das beantworten, habe ich keine Ahnung, welche Klassen erforderlich sein können. Versuchen Sie, eine Ökologie mit Fleisch- und Pflanzenfressern und Pflanzen zu modellieren, die Artenpopulationen in die Zukunft projiziert? Versuchen Sie, den Computer 20 Fragen spielen zu lassen?
Es ist Zeitverschwendung, mit dem Design zu beginnen, bevor Anwendungsfälle definiert wurden. Ich habe gesehen, dass dies zu lächerlichen Extremen geführt hat, als ein Team von ungefähr zehn Mitarbeitern begann, ein OO-Modell einer Fluggesellschaft mithilfe von Software anhand von Bildern zu produzieren. Sie arbeiteten zwei Jahre lang am Modellieren, ohne das eigentliche Geschäftsproblem im Auge zu behalten. Schließlich hatte der Kunde das Warten satt und bat das Team, ein tatsächliches Problem zu lösen. All diese Modellierung war völlig nutzlos.
quelle