Ist das ein schlechtes OOP-Design für eine Simulation mit Schnittstellen?

13

Ich entwerfe mein eigenes kleines OOP-Programm zur Simulation von Vampiren, Wölfen, Menschen und Lastwagen und versuche, mein eigenes begrenztes Verständnis von Schnittstellen zu implementieren.

( Ich abstrahiere hier noch und habe noch keine Code-Implementierung, es ist also eher eine Frage des OOP-Designs ... denke ich!)

Habe ich Recht , wenn ich nach einem „gemeinsamen Verhalten“ zwischen diesen Klassen suche und sie als Schnittstellen implementiere ?

Zum Beispiel, Vampire und Wölfe beißen ... sollte ich also ein Biss-Interface haben?

public class Vampire : Villain, IBite, IMove, IAttack

Ebenso für Trucks ...

public class Truck : Vehicle, IMove

Und für Menschen ...

public class Man : Human, IMove, IDead

Ist mein Denken hier richtig? (Schätze deine Hilfe)

user3396486
quelle
14
Tiere, Gemüse und Mineralien sind selten gute Beispiele für Anwendungsimplementierungen. Die tatsächlichen Implementierungen sind in der Regel abstrakt, wie IEnumerable, IEquatableetc.
Robert Harvey
6
Sie haben eine einzige Erwähnung, was Ihre Objekte in Ihrer Software tun werden ("Biss"). Software ist normalerweise dafür ausgelegt , etwas zu tun , und es ist nicht zielführend, ein Objektmodell nur auf Eigenschaften abzustützen.
Tofro
@tofro Ich wollte, dass IBite mehrere Methoden enthält, die Verhalten in Bezug auf (1) das Verringern des Lebens- / Energie-Niveaus eines anderen (2) das Erscheinen oder Aufrufen von "Blut" -Grafiken und (3) das Aktualisieren der Simulationsstatik umsetzen Daten (wie NoOfBites). Ich denke, ich kann verstehen, dass eine Schnittstelle am besten verwendet wird, um eine Reihe von Methodenverhalten zu implementieren.
user3396486
2
Implementieren die Klassen Human, Vampire und Vehicle die IMove-Schnittstelle nicht bereits? Warum müssen Sie die Unterklassen zu explizit implementieren lassen?
Pierre Arlaud
Sind all diese Schnittstellen wirklich notwendig? In Python brauchst du zum Glück nichts von alledem, was eine wirklich erfrischende Veränderung war (meine erste Sprache war Object Pascal). In manchen Fällen sind auch virtuelle Methoden eine bessere Lösung.
Ajasja

Antworten:

33

Im Allgemeinen möchten Sie Schnittstellen für gemeinsame Merkmale Ihrer Klasse haben.

Ich stimme in den Kommentaren halb mit @Robert Harvey überein, der sagte, dass Schnittstellen normalerweise abstraktere Merkmale von Klassen darstellen. Trotzdem empfinde ich es als eine gute Möglichkeit, ausgehend von konkreten Beispielen abstrakt zu denken.

Während Ihr Beispiel technisch korrekt ist (dh ja, sowohl Vampire als auch Wölfe beißen, so dass Sie eine Schnittstelle dafür haben können), ist es eine Frage von Relevanz. Jedes Objekt hat Tausende von Eigenschaften (z. B. können Tiere Fell haben, schwimmen, Bäume besteigen usw.). Wirst du ein Interface für alle machen? Sehr unwahrscheinlich.

Normalerweise möchten Sie, dass Schnittstellen für sinnvolle Dinge in einer Anwendung als Ganzes zusammengefasst werden. Wenn Sie beispielsweise ein Spiel erstellen, können Sie über eine Reihe von IMove-Objekten verfügen und deren Position aktualisieren. Wenn Sie das nicht möchten, ist die IMove-Oberfläche ziemlich nutzlos.

Der Punkt ist, nicht zu viel Ingenieur. Sie müssen überlegen, wie Sie diese Schnittstelle verwenden möchten, und 2 Klassen mit einer gemeinsamen Methode sind kein ausreichender Grund, eine Schnittstelle zu erstellen.

Paul92
quelle
1
Ich hoffe sicherlich, dass jedes Objekt nicht Tausende von Attributen hat.
Gardenhead
4
Attribute, nicht wie in oop-Attributen, sondern Grammatikattribute / -eigenschaften (Dinge wie z. B. zählbar, vergleichbar usw.): D. Schlechte Wortwahl.
Paul92
3
Beachten Sie, dass die nützlichen Schnittstellen diejenigen sind, die Sie verwenden werden. Zum Beispiel IBiteist es nicht besonders nützlich, aber Sie möchten vielleicht, dass IAttackSie über alle Dinge IUpdateIPhysicsEnabled
hinwegarbeiten
1
Diese Antwort wirft einige sehr gute Punkte auf. Der letzte Absatz fasst es ziemlich gut zusammen; mindestens so gut wie möglich mit dem angegebenen Detaillierungsgrad.
Leichtigkeit Rennen mit Monica
1
Die Gruppierung von Commons-Methoden eignet sich eher für abstrakte Klassen. Es werden Schnittstellen zum Entwerfen von Verträgen erstellt, die diejenigen berücksichtigen müssen, die sie implementieren, und nicht dieselbe Implementierung für einige Objekte gruppieren.
Walfrat
28

Sieht so aus, als würden Sie eine Reihe von Schnittstellen für einzelne Methoden erstellen . Dies ist auf den ersten Blick in Ordnung, aber denken Sie daran, dass die Schnittstellen nicht den Klassen gehören, die sie implementieren. Sie gehören den Kunden, die sie verwenden. Die Kunden entscheiden, ob etwas etwas sein muss, das sich bewegen und angreifen kann.

Wenn ich eine CombatKlasse mit einer fight()Methode habe, muss diese Methode wahrscheinlich sowohl move()als auch attack()für dasselbe Objekt aufgerufen werden. Dies deutet stark auf die Notwendigkeit einer ICombatantSchnittstelle hin, fight()die auf- move()und attack()durchgehen kann. Dies ist sauberer als fight()ein IAttackObjekt zu nehmen und es zu werfen, um IMovezu sehen, ob es sich auch bewegen kann.

Das bedeutet nicht, dass Sie keine IMove IAttackSchnittstellen haben können. Ich hoffe nur, dass Sie sie nicht machen, ohne dass ein Kunde sie braucht. Umgekehrt, wenn kein Client jemals ein Objekt bewegen und angreifen muss, ICombatantist dies nicht erforderlich.

Diese einfache Sichtweise auf Schnittstellen geht oft verloren, weil die Leute gerne Beispiele befolgen. Die ersten Schnittstellen, denen wir ausgesetzt sind, befinden sich in Bibliotheken. Leider haben Bibliotheken keine Ahnung, was ihre Kunden sind. Sie können also nur die Bedürfnisse ihrer Kunden erraten. Nicht das beste Beispiel zu folgen.

kandierte_orange
quelle
1
Verdammt, das ist gut. Gaming scheint einfach eine wirklich gute Möglichkeit zu sein, OOP zu benutzen und zu erklären.
JeffO
6
@JeffO, bis Sie tatsächlich ein relativ großes Spiel implementieren und feststellen, dass OOP ein heißes Durcheinander ist und Sie mit komponentenbasierten Systemen oder datenorientierten Designs besser dran sind.
Darkhogg
"Schnittstellen gehören den Clients, die sie verwenden"
Tibos
1
+1 für den Unterschied zwischen Bibliotheken und Anwendungen, ich lese oft (zu viel?: /) Tonnen von Dingen, die nur für das eine und nicht für das andere passen.
Walfrat
3

Überlegen Sie, ob es üblich sein wird, Sammlungen von Objekten mit unterschiedlichen Kombinationen von Fähigkeiten zu haben, und ob Code möglicherweise eine Aktion für die Elemente innerhalb einer Sammlung ausführen möchte, die diese unterstützen . Wenn ja, und wenn es ein vernünftiges "Standardverhalten" für Objekte gibt, die für bestimmte Aktionen keine nützliche Unterstützung bieten, kann es hilfreich sein, Schnittstellen von einer Vielzahl von Klassen implementieren zu lassen, nicht nur von solchen, die sich nützlich verhalten können.

Nehmen wir zum Beispiel an, nur wenige Arten von Kreaturen können Woozles haben, und man möchte, dass solche Kreaturen eine NumerOfWoozlesEigenschaft haben. Wenn eine solche Eigenschaft in einer Schnittstelle vorhanden wäre, die nur von Kreaturen implementiert wurde, die Woozles haben können, müsste der Code, der die Gesamtzahl der Woozles ermitteln möchte, die von einer Sammlung von Kreaturen gemischter Typen gehalten werden, etwa Folgendes sagen:

int total = 0;
foreach (object it in creatures)
{
   IWoozleCountable w = trycast(it, IWoozleCountable);
   if (w != null) total += w.WoozleCount;
}

Wenn jedoch WoozleCount ein Mitglied von Creature / ICreature wäre, könnte der Code wie folgt vereinfacht werden:

int total = 0;
foreach (ICreature it in creatures)
   total += it.WoozleCount;

Während einige Leute auf der Idee scheuern könnten eine WoozleCount Eigenschaft jede Kreatur implementieren zu haben , die wirklich für einige Subtypen nur dann sinnvoll ist, würde die Eigenschaft sein sinnvoll für alle, auch nicht , dass es mit Gegenständen nützlich sein , bekannt diesen Typs zu sein, und ich würde die "Küchenspüle" -Schnittstelle als weniger nach Code riechend betrachten als den Trycast-Operator.

Superkatze
quelle