Ein bekannter Mangel der traditionellen Klassenhierarchien ist, dass sie schlecht sind, wenn es darum geht, die reale Welt zu modellieren. Als Beispiel soll versucht werden, Tierarten mit Klassen darzustellen. Dabei gibt es tatsächlich mehrere Probleme, aber eines, für das ich nie eine Lösung gesehen habe, ist, wenn eine Unterklasse ein Verhalten oder eine Eigenschaft "verliert", die in einer Superklasse definiert wurde, wie ein Pinguin, der nicht fliegen kann (dorthin) sind wahrscheinlich bessere Beispiele, aber das ist das erste, das mir in den Sinn kommt).
Einerseits möchten Sie nicht für jede Eigenschaft und jedes Verhalten ein Flag definieren, das angibt, ob es überhaupt vorhanden ist, und es jedes Mal überprüfen, bevor Sie auf dieses Verhalten oder diese Eigenschaft zugreifen. Sie möchten nur sagen, dass Vögel in der Vogelklasse einfach und klar fliegen können. Aber dann wäre es schön, wenn man hinterher "Ausnahmen" definieren könnte, ohne überall ein paar schreckliche Hacks verwenden zu müssen. Dies ist häufig der Fall, wenn ein System längere Zeit produktiv war. Sie finden plötzlich eine "Ausnahme", die überhaupt nicht in das ursprüngliche Design passt, und Sie möchten nicht einen großen Teil Ihres Codes ändern, um ihn aufzunehmen.
Gibt es also einige Sprach- oder Entwurfsmuster, die dieses Problem sauber handhaben können, ohne dass größere Änderungen an der "Superklasse" und dem gesamten Code, der sie verwendet, erforderlich sind? Selbst wenn eine Lösung nur einen bestimmten Fall behandelt, können mehrere Lösungen zusammen eine vollständige Strategie bilden.
Nachdem ich mehr nachgedacht habe, wird mir klar, dass ich das Liskov-Substitutionsprinzip vergessen habe. Deshalb kannst du es nicht tun. Angenommen, Sie definieren "Merkmale / Schnittstellen" für alle wichtigen "Merkmalsgruppen", können Sie Merkmale in verschiedenen Zweigen der Hierarchie frei implementieren, so wie das Flugmerkmal von Vögeln und einigen besonderen Arten von Eichhörnchen und Fischen implementiert werden könnte.
Meine Frage könnte also lauten: "Wie kann ich ein Merkmal deaktivieren?" Wenn Ihre Superklasse eine Java-serialisierbare Klasse ist, müssen Sie auch eine sein, auch wenn Sie Ihren Status nicht serialisieren können, z. B. wenn Sie einen "Socket" enthalten haben.
Eine Möglichkeit, dies zu tun, besteht darin, alle Ihre Merkmale von Anfang an paarweise zu definieren: Fliegen und NotFlying (was eine UnsupportedOperationException auslösen würde, wenn nicht dagegen geprüft). Das Merkmal Nicht definiert keine neue Schnittstelle und kann einfach überprüft werden. Klingt nach einer "billigen" Lösung, insbesondere wenn sie von Anfang an verwendet wird.
" it would be nice if one could define "exceptions" afterward, without having to use some horrible hacks everywhere"
Halten Sie eine Factory-Methode zur Verhaltenskontrolle für hacky?
NotSupportedException
aus Penguin.fly()
.
class Penguin < Bird; undef fly; end;
. Ob Sie sollten, ist eine andere Frage.
function save_yourself_from_crashing_airplane(Bird b) { f.fly() }
das viel komplizierter wird. (wie Peter Török sagte, es verletzt LSP)