Was sind die Unterschiede zwischen abstrakten Klassen, Interfaces und wann sie verwendet werden sollen?


15

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!


Es gibt viele gute Beispiele online. Ich denke, das ist einer von ihnen. javapapers.com/core-java/abstract-and-interface-core-java-2/…
Siva

Antworten:


26

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:

class Bird extends Animal implements Flight;
class Plane extends Vehicle implements Flight, AccountableAsset;
class Mosquito extends Animal implements Flight;
class Horse extends Animal;
class RaceHorse extends Horse implements AccountableAsset;
class Pegasus extends Horse implements Flight;

Bird, MosquitoUnd Horse sind Animals . Sie sind verwandt. Sie erben gängige Methoden von Animal like eat(), 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().

Planeist nicht verwandt mit Bird, Mosquitooder Horse.

Flightwird von unterschiedlichen, nicht verwandten Klassen wie Birdund implementiert Plane.

AccountableAssetwird auch von unterschiedlichen, nicht verwandten Klassen wie Planeund implementiert RaceHorse.

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, AccountableAssetsunabhängig davon, ob RaceHorsesoder Planes.


Tolle. Interface bietet einen bestimmten Funktionsbereich, der festlegt, can do/can be treated aswo abstrakte Klassen als Grundlage dienen!
Abhiroj Panwar

13

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.


3

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


2
Classes cannot have multiple inheritance- Richtig für Sprachen wie Java und C #, nicht für C ++.
Robert Harvey

3

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.


3

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 Employeeund der Unterschied in abgeleiteten Klassen wie Manageroder Workerusw. 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 LeaveCalculatorSchnittstelle mit einem Calculate()unterschiedlichen Verhalten implementieren können .


-3
  1. Der Hauptunterschied besteht darin, dass Methoden einer Java-Schnittstelle implizit abstrakt sind und keine Implementierungen aufweisen können. Eine abstrakte Java-Klasse kann über Instanzmethoden verfügen, die ein Standardverhalten implementieren.
  2. In einer Java-Schnittstelle deklarierte Variablen sind standardmäßig final. Eine abstrakte Klasse kann nicht endgültige Variablen enthalten.
  3. Mitglieder einer Java-Schnittstelle sind standardmäßig öffentlich. Eine abstrakte Java-Klasse kann die üblichen Eigenschaften von Klassenmitgliedern wie privat, geschützt usw. haben.
  4. Die Java-Schnittstelle sollte mit dem Schlüsselwort "implements" implementiert werden. Eine Java-abstrakte Klasse sollte mit dem Schlüsselwort "extend" erweitert werden.
  5. Eine Schnittstelle kann eine andere Java-Schnittstelle erweitern. Nur eine abstrakte Klasse kann eine andere Java-Klasse erweitern und mehrere Java-Schnittstellen implementieren.
  6. Eine Java-Klasse kann mehrere Schnittstellen implementieren, aber nur eine abstrakte Klasse erweitern.
  7. Die Schnittstelle ist absolut abstrakt und kann nicht instanziiert werden. Eine abstrakte Java-Klasse kann ebenfalls nicht instanziiert werden, kann jedoch aufgerufen werden, wenn ein main () vorhanden ist.
  8. Im Vergleich zu Java-Abstraktionsklassen sind Java-Schnittstellen langsam, da zusätzliche Indirektion erforderlich ist.
  9. Schnittstelle und abstrakte Klasse in Java ist, dass Sie keine nicht abstrakte Methode in der Schnittstelle erstellen können. Jede Methode in der Schnittstelle ist standardmäßig abstrakt. Sie können jedoch eine nicht abstrakte Methode in der abstrakten Klasse erstellen.
  10. Abstrakte Klasse vs. Schnittstelle in Java ist, dass Schnittstellen besser für die Typdeklaration geeignet sind und abstrakte Klasse besser für die Wiederverwendung von Code und die Evolutionsperspektive geeignet ist.
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.