Wann werden Interfaces oder abstrakte Klassen verwendet? Wann beides verwenden?
Während bestimmte Richtlinien vorschreiben, dass Sie eine Schnittstelle verwenden sollten, wenn Sie einen Vertrag für eine Klasse definieren möchten, bei der die Vererbung nicht klar ist (IDomesticated
) und Vererbung, wenn die Klasse eine Erweiterung einer anderen ist (Cat : Mammal
, Snake : Reptile
), gibt es Fälle, in denen (meiner Meinung nach) diese Richtlinien in einen grauen Bereich eintreten.
Angenommen, meine Implementierung warCat : Pet
. Pet
ist eine abstrakte Klasse. Sollte das erweitert werden aufCat : Mammal, IDomesticated
woherMammal
ist eine abstrakte Klasse undIDomesticated
ist eine Schnittstelle? Oder stehe ich im Konflikt mit derKUSS/YAGNI Prinzipien (auch wenn ich nicht sicher bin, ob es eine geben wird)Wolf
Klasse in der Zukunft, die nicht in der Lage wäre, von zu erbenPet
)?
Weg vom MetaphorischenCat
s undPet
Angenommen, ich habe einige Klassen, die Quellen für eingehende Daten darstellen. Sie alle müssen irgendwie dieselbe Basis implementieren. Ich könnte einen generischen Code in einer Zusammenfassung implementierenSource
Klasse und erben davon. Ich könnte auch einfach eine machenISource
Benutzeroberfläche (die sich für mich "richtiger" anfühlt) und den generischen Code in jeder Klasse neu implementieren (was weniger intuitiv ist). Schließlich konnte ich "den Kuchen haben und ihn essen", indem ich sowohl die abstrakte Klasse als auch die Schnittstelle erstellte. Was ist am besten
In diesen beiden Fällen wird darauf hingewiesen, dass nur eine abstrakte Klasse, nur eine Schnittstelle und sowohl eine abstrakte Klasse als auch eine Schnittstelle verwendet werden. Sind das alles gültige Entscheidungen, oder gibt es "Regeln", nach denen eine über eine andere gestellt werden soll?
Ich möchte das klarstellen, indem ich "sowohl eine abstrakte Klasse als auch eine Schnittstelle benutze", die den Fall einschließt, in dem sie im Wesentlichen dasselbe darstellen (Source
undISource
beide haben die gleichen Mitglieder), aber die Klasse fügt generische Funktionen hinzu, während die Schnittstelle den Vertrag spezifiziert.
Erwähnenswert ist auch, dass diese Frage hauptsächlich für Sprachen gilt, die keine Mehrfachvererbung unterstützen (z. B. .NET und Java).