Vor kurzem habe ich angefangen, mich mit OOP zu beschäftigen, und jetzt bin ich so weit, dass ich umso verwirrter werde, je mehr ich über die Unterschiede zwischen abstrakten Klassen und Schnittstellen lese. Bisher kann keiner von beiden instanziiert werden. Schnittstellen sind mehr oder weniger strukturelle Entwürfe, die das Gerüst bestimmen, und Zusammenfassungen unterscheiden sich dadurch, dass sie Code teilweise implementieren können.
Ich möchte mehr über diese durch meine spezifische Situation lernen. Hier ist ein Link zu meiner ersten Frage, wenn Sie ein wenig mehr Hintergrundinformationen wünschen: Was ist ein gutes Designmodell für meine neue Klasse?
Hier sind zwei Klassen, die ich erstellt habe:
class Ad {
$title;
$description
$price;
function get_data($website){ }
function validate_price(){ }
}
class calendar_event {
$title;
$description
$start_date;
function get_data($website){ //guts }
function validate_dates(){ //guts }
}
Sie sehen also, dass diese Klassen fast identisch sind. Hier nicht gezeigt, aber es gibt andere Funktionen like get_zip()
, save_to_database()
die in meinen Klassen üblich sind. Ich habe auch andere Klassen Cars and Pets hinzugefügt, die alle gängigen Methoden und natürlich die für diese Klassen spezifischen Eigenschaften aufweisen (z. B. Kilometerstand, Gewicht).
Jetzt habe ich gegen das DRY- Prinzip verstoßen und verwalte und ändere denselben Code in mehreren Dateien. Ich habe vor, mehr Klassen wie Boote, Pferde oder was auch immer zu haben.
Also würde ich hier eine Schnittstelle oder eine abstrakte Klasse verwenden? Soweit ich mit abstrakten Klassen vertraut bin, würde ich eine Superklasse als Vorlage mit allen in die abstrakte Klasse eingebauten gemeinsamen Elementen verwenden und dann nur die Elemente hinzufügen, die in zukünftigen Klassen speziell benötigt werden. Beispielsweise:
abstract class content {
$title;
$description
function get_data($website){ }
function common_function2() { }
function common_function3() { }
}
class calendar_event extends content {
$start_date;
function validate_dates(){ }
}
Oder würde ich eine Schnittstelle verwenden und, weil diese so ähnlich sind, eine Struktur erstellen, die jede Unterklasse aus Integritätsgründen verwenden muss, und es dem Endentwickler überlassen, der diese Klasse ausarbeitet, um für jede der Klassen verantwortlich zu sein Details sogar der allgemeinen Funktionen. Meiner Meinung nach müssen einige "gemeinsame" Funktionen in Zukunft möglicherweise an die Bedürfnisse ihrer jeweiligen Klasse angepasst werden.
Trotz alledem, wenn Sie glauben, dass ich das Was und Warum von abstrakten Klassen und Schnittstellen insgesamt missverstehe, lassen Sie auf jeden Fall eine gültige Antwort zu, damit Sie aufhören, in diese Richtung zu denken, und schlagen Sie den richtigen Weg vor, um fortzufahren!
Vielen Dank!
quelle
Antworten:
In den Begriffen des Laien:
Schnittstellen sind für die Art von Beziehungen, die "tun können / können behandelt werden" .
Abstrakte (wie auch konkrete) Klassen sind für "ist eine" Art von Beziehung.
Schau 'dir diese Beispiele an:
Bird
,Mosquito
UndHorse
sindAnimals
. Sie sind verwandt. Sie erben gängige Methoden von Animal likeeat(), metabolize() and reproduce()
. Vielleicht überschreiben sie diese Methoden und fügen ihnen ein kleines Extra hinzu, aber sie nutzen das Standardverhalten, das in Animal like implementiert istmetabolizeGlucose().
Plane
ist nicht verwandt mitBird
,Mosquito
oderHorse
.Flight
wird von unterschiedlichen, nicht verwandten Klassen wieBird
und implementiertPlane
.AccountableAsset
wird auch von unterschiedlichen, nicht verwandten Klassen wiePlane
und implementiertRaceHorse
.Horse
implementiert Flight nicht.Wie Sie sehen können, können Sie mit Klassen (abstrakt oder konkret) Hierarchien aufbauen und Code von den oberen bis zu den unteren Ebenen der Hierarchie übernehmen. Theoretisch ist Ihr Verhalten umso spezialisierter, je niedriger Sie in der Hierarchie sind, aber Sie müssen sich nicht um viele Dinge kümmern, die bereits erledigt sind.
Schnittstellen hingegen erstellen keine Hierarchie, können jedoch dazu beitragen, bestimmte Verhaltensweisen über Hierarchien hinweg zu homogenisieren, sodass Sie sie in bestimmten Kontexten von der Hierarchie abstrahieren können.
Zum Beispiel kann ein Programm den Wert einer Gruppe summieren,
AccountableAssets
unabhängig davon, obRaceHorses
oderPlanes
.quelle
can do/can be treated as
wo abstrakte Klassen als Grundlage dienen!Sie könnten die Antwort logisch ableiten, da Sie die Unterschiede zwischen den beiden zu kennen scheinen.
Schnittstellen definieren einen gemeinsamen Vertrag. Zum Beispiel eine Schnittstelle namens IAnimal, bei der alle Tiere Funktionen wie Eat (), Move (), Attack () usw. gemeinsam nutzen. Während alle die gleichen Funktionen haben, haben alle oder die meisten von ihnen eine andere Art (Implementierung), dies zu erreichen es.
Abstrakte Klassen definieren eine gemeinsame Implementierung und optional gemeinsame Verträge. Zum Beispiel könnte ein einfacher Taschenrechner als abstrakte Klasse gelten, die alle grundlegenden logischen und bitweisen Operatoren implementiert und dann um ScientificCalculator, GraphicalCalculator usw. erweitert wird.
Wenn Sie eine gemeinsame Implementierung haben, kapseln Sie die Funktionalität auf jeden Fall in eine abstrakte Klasse, von der aus sie erweitert werden kann. Ich habe fast 0 PHP-Erfahrung, aber ich glaube nicht, dass Sie Schnittstellen mit nicht konstanten Feldern erstellen können. Wenn die Felder in Ihren Instanzklassen identisch sind, müssen Sie eine Abstract-Klasse verwenden, es sei denn, Sie definieren den Zugriff auf sie über Getter und Setter.
Auch bei Google scheint es keinen Mangel an Ergebnissen zu geben.
quelle
Um es kurz zu machen. Abstrakte Klassen ähneln insofern Interfaces, als sie beide eine Vorlage dafür liefern, welche Methoden in der übernehmenden Klasse enthalten sein sollen, aber es gibt große Unterschiede: - Interfaces definieren nur Namen / Arten von Methoden, die in einer übernehmenden Klasse vorhanden sein müssen, während sie keine Klassen können einen vollständigen Standardmethodencode haben und nur die Details müssen möglicherweise überschrieben werden. - Schnittstellen können keine Zugriffsmodifikatoren haben. - Schnittstellen dürfen keine Felder haben. - Klassen können keine Mehrfachvererbung von Klassen haben, während sie mehrere Schnittstellen erben können. - Außerdem bieten Klassen eine Hierarchiestruktur, sodass nur Klassen, die von einer bestimmten Klasse abgeleitet sind, den Richtlinien der abstrakten Klasse folgen müssen: Objekt-> bestimmtes Objekt-> sehr bestimmtes Objekt. Schnittstellen hingegen können von jedem an jedem Ort geerbt werden.
Meiner Meinung nach sind abstrakte Klassen häufiger, da sie die Standardimplementierung von Code sofort bereitstellen können. In großen Projekten, in denen Sie bestimmte Klassen standardisieren müssen, können Schnittstellen jedoch nützlich sein.
Ich hoffe, das hilft, aber es gibt viele Informationen online, Leo
quelle
Classes cannot have multiple inheritance
- Richtig für Sprachen wie Java und C #, nicht für C ++.Zunächst sollten Sie verstehen, dass Sie häufig sowohl eine Schnittstelle als auch eine abstrakte Klasse bereitstellen. Der Grund dafür und der Hauptunterschied zwischen den beiden besteht darin, dass Sie mit ihnen unterschiedlichen Code wiederverwenden und so unterschiedliche Probleme lösen können.
Mithilfe von Schnittstellen können Sie Clientcode mit verschiedenen Implementierungen wiederverwenden. Ein Client Ihrer Klasse get_data ($ website) kümmert sich nicht um die Elemente $ title oder $ description. Es möchte nur Ihren Inhalt anweisen, die Daten zu laden. Wenn Sie unterschiedliche Arten von Inhalten haben, von denen einige eine $ description benötigen und andere keine, können Sie eine ContentInterface-Klasse bereitstellen, die nur die Signatur Ihrer untergeordneten Klassen angibt. Jetzt kann der Client eine beliebige Anzahl unterschiedlicher Inhalte haben, ohne dass jeder genau weiß, wie sie funktionieren. Das Liskov-Substitutionsprinzip ist eine gute Lektüre, um diese Idee zu studieren. Ich mag es auch, wenn Onkel Bob über das Thema schreibt. Schnittstellen sind für Unit-Tests sehr wichtig, und das Erstellen von Schnittstellen ist eine gute Angewohnheit zum Lernen.
Mit abstrakten Klassen können Sie allgemeine Implementierungsdetails für eine Reihe von Klassen wiederverwenden, die einen gemeinsamen Vorfahren haben. In Ihrer Frage scheinen Sie einen guten Überblick darüber zu haben, warum Sie die Implementierung von einer abstrakten Klasse erben würden. Es ist immer noch gefährlich, sich auf die Interna einer Basisklasse zu verlassen - es ist sehr einfach, die Kapselung zu verletzen und Kinder zu erstellen, die von bestimmten Implementierungsdetails einer Basisklasse abhängen. Das Vorlagenmethodenmuster bietet ein allgemeines und fehlerfreies Beispiel für die Verwendung von Basisklassen, ohne die Kapselung zu verletzen.
Wie ich hoffe, werden Sie daher häufig Schnittstellen für die Clients Ihrer Klassenhierarchie bereitstellen, damit Sie Ihre Implementierung sicher ändern können, ohne den Clientcode zu beeinträchtigen. Auf diese Weise kann der Client Komponententests mit Mock Objects schreiben , die Ihre Schnittstelle erben. Außerdem stellen Sie abstrakte Klassen bereit, mit denen Sie die allgemeine Logik wiederverwenden oder die Semantik für die untergeordneten Klassen erzwingen können.
quelle
Der Unterschied ist subtil, aber klar. Die Schnittstelle handelt von polymorphem Verhalten. In der abstrakten Klasse geht es um Wiederverwendung und polymorphes Verhalten.
Wenn Sie Wert auf Wiederverwendung und polymorphes Verhalten legen möchten, wählen Sie abstrakte Klasse. Zum Beispiel haben verschiedene Arten von Mitarbeitern unterschiedliche Bestimmungen, aber alle erhalten einige gemeinsame Bestimmungen. Abstrakte Klassen eignen sich also zur Darstellung, da Gemeinsamkeiten in einer abstrakten Basisklasse ausgedrückt werden können
Employee
und der Unterschied in abgeleiteten Klassen wieManager
oderWorker
usw. implementiert werden kann .Wenn Sie nur das polymorphe Verhalten betonen möchten, wählen Sie die Schnittstelle. Bei der Schnittstelle handelt es sich eher um einen Vertrag, dh ein Objekt oder eine Hierarchie, die besagt, dass es einem bestimmten Verhalten entspricht. Zum Beispiel haben alle Mitarbeiter eine Urlaubsvorsorge, aber unterschiedliche Arten von Mitarbeitern haben unterschiedliche Arten von Rückstellungen. Jeder Mitarbeitertyp benötigt also einen anderen Urlaubsrechner. Hier ist die Schnittstelle eine gute Wahl, da alle Arten von Mitarbeitern eine
LeaveCalculator
Schnittstelle mit einemCalculate()
unterschiedlichen Verhalten implementieren können .quelle
quelle