Dies kann eine allgemeine OOP-Frage sein. Ich wollte einen generischen Vergleich zwischen einer Schnittstelle und einer abstrakten Klasse auf der Grundlage ihrer Verwendung durchführen.
Wann möchte man eine Schnittstelle verwenden und wann möchte man eine abstrakte Klasse verwenden ?
oop
inheritance
interface
abstract-class
Chirantan
quelle
quelle
Antworten:
Ich habe einen Artikel darüber geschrieben:
Abstrakte Klassen und Schnittstellen
Zusammenfassend:
Wenn wir über abstrakte Klassen sprechen, definieren wir Merkmale eines Objekttyps. Angeben, was ein Objekt ist .
Wenn wir über eine Schnittstelle sprechen und Funktionen definieren, die wir bereitstellen möchten, sprechen wir über den Abschluss eines Vertrags darüber, was das Objekt tun kann.
quelle
Interfaces do not express something like "a Doberman is a type of dog and every dog can walk" but more like "this thing can walk"
. Vielen DankUse abstract classes and inheritance if you can make the statement “A is a B”. Use interfaces if you can make the statement “A is capable of [doing] as”
Eine abstrakte Klasse kann einen gemeinsamen Status oder eine gemeinsame Funktionalität haben. Eine Schnittstelle ist nur ein Versprechen, den Status oder die Funktionalität bereitzustellen. Eine gute abstrakte Klasse reduziert die Menge an Code, die neu geschrieben werden muss, da die Funktionalität oder der Status gemeinsam genutzt werden können. Die Schnittstelle verfügt über keine definierten Informationen, die gemeinsam genutzt werden sollen
quelle
Persönlich muss ich fast nie abstrakte Klassen schreiben.
Meistens sehe ich, dass abstrakte Klassen (falsch) verwendet werden, weil der Autor der abstrakten Klasse das Muster "Vorlagenmethode" verwendet.
Das Problem mit der "Template-Methode" ist, dass sie fast immer etwas neu ist - die "abgeleitete" Klasse kennt nicht nur die "abstrakte" Methode ihrer Basisklasse, die sie implementiert, sondern auch die öffentlichen Methoden der Basisklasse , obwohl es meistens nicht nötig ist, sie anzurufen.
(Zu stark vereinfacht) Beispiel:
Hier hat der Autor dieser Klasse einen generischen Algorithmus geschrieben und beabsichtigt, dass die Benutzer ihn verwenden, indem sie ihn "spezialisieren", indem sie ihre eigenen "Hooks" bereitstellen - in diesem Fall eine "Vergleichs" -Methode.
Die beabsichtigte Verwendung ist also ungefähr so:
Das Problem dabei ist, dass Sie zwei Konzepte übermäßig miteinander verbunden haben:
Im obigen Code kann der Autor der "compare" -Methode theoretisch die "Sort" -Methode der Oberklasse erneut aufrufen ... obwohl er dies in der Praxis niemals tun möchte oder muss.
Der Preis, den Sie für diese nicht benötigte Kopplung zahlen, ist, dass es schwierig ist, die Oberklasse zu ändern, und in den meisten OO-Sprachen ist es unmöglich, sie zur Laufzeit zu ändern.
Die alternative Methode besteht darin, stattdessen das Entwurfsmuster "Strategie" zu verwenden:
Beachten Sie jetzt: Wir haben nur Schnittstellen und konkrete Implementierungen dieser Schnittstellen. In der Praxis brauchen Sie eigentlich nichts anderes, um ein OO-Design auf hohem Niveau zu erstellen.
Um die Tatsache zu "verbergen", dass wir die "Sortierung von Namen" mithilfe einer "QuickSort" -Klasse und eines "NameComparator" implementiert haben, schreiben wir möglicherweise noch irgendwo eine Factory-Methode:
Jedes Mal, wenn Sie eine abstrakte Klasse haben, können Sie dies tun ... selbst wenn eine natürliche Wiedereintrittsbeziehung zwischen der Basisklasse und der abgeleiteten Klasse besteht, lohnt es sich normalerweise, sie explizit zu machen.
Ein letzter Gedanke: Alles, was wir oben getan haben, ist, eine "NameSorting" -Funktion mit einer "QuickSort" -Funktion und einer "NameComparison" -Funktion zu "komponieren". In einer funktionalen Programmiersprache wird dieser Programmierstil noch natürlicher. mit weniger Code.
quelle
Wenn Sie Java als OOP-Sprache betrachten,
" Schnittstelle bietet keine Methodenimplementierung " ist beim Start von Java 8 nicht mehr gültig. Jetzt bietet Java die Implementierung in der Schnittstelle für Standardmethoden.
In einfachen Worten möchte ich verwenden
Schnittstelle: Um einen Vertrag durch mehrere unabhängige Objekte zu implementieren. Es bietet " HAS A " -Funktion.
abstrakte Klasse: Um dasselbe oder ein unterschiedliches Verhalten zwischen mehreren verwandten Objekten zu implementieren. Es stellt dieBeziehung" IS A " her.
Die Oracle- Website bietet wichtige Unterschiede zwischen
interface
undabstract
Klasse.Verwenden Sie abstrakte Klassen, wenn:
Erwägen Sie die Verwendung von Schnittstellen, wenn:
Serializable
Schnittstelle implementieren .Beispiel:
Abstrakte Klasse ( IS A Relation)
Reader ist eine abstrakte Klasse.
BufferedReader ist ein
Reader
FileReader ist ein
Reader
FileReader
undBufferedReader
werden für allgemeine Zwecke verwendet: Lesen von Daten, und sie sind durchReader
Klasse verbunden.Schnittstelle ( HAT A- Fähigkeit)
Serializable ist eine Schnittstelle.
Angenommen, Ihre Anwendung enthält zwei Klassen, die die
Serializable
Schnittstelle implementierenEmployee implements Serializable
Game implements Serializable
Hier können Sie keine Beziehung durch die
Serializable
Schnittstelle zwischenEmployee
und herstellenGame
, die für verschiedene Zwecke bestimmt sind. Beide sind in der Lage, den Staat zu serialisieren, und der Vergleich endet dort.Schauen Sie sich diese Beiträge an:
Wie hätte ich den Unterschied zwischen einer Interface- und einer Abstract-Klasse erklären sollen?
quelle
OK, ich habe das gerade selbst "grokked" - hier ist es in Laienbegriffen (zögern Sie nicht, mich zu korrigieren, wenn ich falsch liege) - ich weiß, dass dieses Thema oooooold ist, aber eines Tages könnte jemand anderes darüber stolpern ...
Mit abstrakten Klassen können Sie einen Entwurf erstellen und zusätzlich Eigenschaften und Methoden CONSTRUCT (implementieren), die ALLE Nachkommen besitzen sollen.
Über eine Schnittstelle können Sie jedoch nur deklarieren, dass Eigenschaften und / oder Methoden mit einem bestimmten Namen in allen Klassen vorhanden sein sollen, die sie implementieren. Sie geben jedoch nicht an, wie Sie sie implementieren sollen. Eine Klasse kann auch VIELE Schnittstellen implementieren, aber nur EINE abstrakte Klasse erweitern. Ein Interface ist eher ein Architekturwerkzeug auf hoher Ebene (was klarer wird, wenn Sie anfangen, Entwurfsmuster zu erfassen) - ein Abstract hat in beiden Lagern einen Fuß und kann auch einen Teil der Drecksarbeit ausführen.
Warum übereinander verwenden? Ersteres ermöglicht eine konkretere Definition von Nachkommen - letzteres ermöglicht einen größeren Polymorphismus . Dieser letzte Punkt ist für den Endbenutzer / Codierer wichtig, der diese Informationen verwenden kann, um den AP I (Schnittstelle) in einer Vielzahl von Kombinationen / Formen zu implementieren , um seinen Anforderungen zu entsprechen.
Ich denke , dass dies die „Glühbirne“ Moment für mich war - man denke über Schnittstellen weniger von der Autoren perpective und mehr von dem eines Coder später in der Kette kommen , die Umsetzung eines Projekts ist das Hinzufügen oder Verlängerung eine API.
quelle
Meine zwei Cent:
Eine Schnittstelle definiert grundsätzlich einen Vertrag, den jede implementierende Klasse einhalten muss (Implementierung der Schnittstellenmitglieder). Es enthält keinen Code.
Andererseits kann eine abstrakte Klasse Code enthalten, und es kann einige Methoden geben, die als abstrakt markiert sind und die eine erbende Klasse implementieren muss.
Die seltenen Situationen, in denen ich abstrakte Klassen verwendet habe, sind, wenn ich einige Standardfunktionen habe, bei denen die erbende Klasse möglicherweise nicht daran interessiert ist, beispielsweise eine abstrakte Basisklasse zu überschreiben, von der einige spezialisierte Klassen erben.
Beispiel (ein sehr rudimentärer ein!): Eine Basisklasse namens Customer betrachten , die wie abstrakte Methoden haben
CalculatePayment()
,CalculateRewardPoints()
und einige nicht-abstrakte Methoden wieGetName()
,SavePaymentDetails()
.Spezialisierte Klassen mögen
RegularCustomer
undGoldCustomer
erben von derCustomer
Basisklasse und implementieren ihre eigeneCalculatePayment()
undCalculateRewardPoints()
Methodenlogik, verwenden jedoch die MethodenGetName()
und erneutSavePaymentDetails()
.Sie können einer abstrakten Klasse (dh nicht abstrakten Methoden) weitere Funktionen hinzufügen, ohne dass sich dies auf untergeordnete Klassen auswirkt, die eine ältere Version verwenden. Das Hinzufügen von Methoden zu einer Schnittstelle würde sich auf alle Klassen auswirken, die sie implementieren, da sie jetzt die neu hinzugefügten Schnittstellenmitglieder implementieren müssten.
Eine abstrakte Klasse mit allen abstrakten Mitgliedern ähnelt einer Schnittstelle.
quelle
Wann zu tun ist, ist eine sehr einfache Sache, wenn Sie das Konzept klar im Kopf haben.
Abstrakte Klassen können abgeleitet werden, während Schnittstellen implementiert werden können. Es gibt einen Unterschied zwischen den beiden. Wenn Sie eine abstrakte Klasse ableiten, ist die Beziehung zwischen der abgeleiteten Klasse und der Basisklasse 'ist eine' Beziehung. Beispiel: Ein Hund ist ein Tier, ein Schaf ist ein Tier, was bedeutet, dass eine abgeleitete Klasse einige Eigenschaften von der Basisklasse erbt.
Während für die Implementierung von Schnittstellen die Beziehung "kann sein" ist. zB kann ein Hund ein Spionagehund sein. Ein Hund kann ein Zirkushund sein. Ein Hund kann ein Rennhund sein. Das bedeutet, dass Sie bestimmte Methoden implementieren, um etwas zu erwerben.
Ich hoffe ich bin klar.
quelle
1.Wenn Sie etwas erstellen, das nicht verwandten Klassen allgemeine Funktionen bietet, verwenden Sie eine Schnittstelle.
2.Wenn Sie etwas für Objekte erstellen, die in einer Hierarchie eng miteinander verbunden sind, verwenden Sie eine abstrakte Klasse.
quelle
Ich habe einen Artikel darüber geschrieben, wann eine abstrakte Klasse und wann eine Schnittstelle verwendet werden soll. Es gibt viel mehr Unterschiede zwischen ihnen als "ein IS-A ... und ein CAN-DO ...". Für mich sind das eingemachte Antworten. Ich erwähne einige Gründe, warum einer von beiden verwendet werden soll. Ich hoffe es hilft.
http://codeofdoom.com/wordpress/2009/02/12/learn-this-when-to-use-an-abstract-class-and-an-interface/
quelle
Ich denke, die prägnanteste Art, es auszudrücken, ist die folgende:
Gemeinsame Eigenschaften => abstrakte Klasse.
Gemeinsame Funktionalität => Schnittstelle.
Und um es weniger prägnant auszudrücken ...
Beispiel für eine abstrakte Klasse:
Da Tiere eine gemeinsame Eigenschaft haben - in diesem Fall die Anzahl der Beine - ist es sinnvoll, eine abstrakte Klasse zu erstellen, die diese gemeinsame Eigenschaft enthält. Auf diese Weise können wir auch allgemeinen Code schreiben, der für diese Eigenschaft ausgeführt wird. Zum Beispiel:
Schnittstellenbeispiel:
Beachten Sie hier, dass Vuvuzelas und Cars völlig unterschiedliche Dinge sind, aber gemeinsame Funktionen haben: einen Sound erzeugen. Daher ist hier eine Schnittstelle sinnvoll. Außerdem können Programmierer Dinge, die Geräusche erzeugen, unter einer gemeinsamen Oberfläche zusammenfassen -
IMakeSound
in diesem Fall. Mit diesem Design können Sie den folgenden Code schreiben:Können Sie sagen, was das ausgeben würde?
Zuletzt können Sie beide kombinieren.
Kombiniertes Beispiel:
Hier müssen alle
BaseAnimal
einen Sound erzeugen, aber wir kennen die Implementierung noch nicht. In einem solchen Fall können wir die Schnittstellenimplementierung abstrahieren und ihre Implementierung an ihre Unterklassen delegieren.Ein letzter Punkt: Erinnern Sie sich daran, wie wir im Beispiel der abstrakten Klasse die gemeinsamen Eigenschaften verschiedener Objekte bearbeiten und im Beispiel der Benutzeroberfläche die gemeinsame Funktionalität verschiedener Objekte aufrufen konnten? In diesem letzten Beispiel könnten wir beides tun.
quelle
Wann ist eine abstrakte Klasse der Schnittstelle vorzuziehen?
Wann sollte eine Schnittstelle der abstrakten Klasse vorgezogen werden?
quelle
Klassen erben möglicherweise nur von einer Basisklasse. Wenn Sie also abstrakte Klassen verwenden möchten, um einer Gruppe von Klassen Polymorphismus zu verleihen, müssen sie alle von dieser Klasse erben. Abstrakte Klassen können auch Mitglieder bereitstellen, die bereits implementiert wurden. Daher können Sie mit einer abstrakten Klasse eine bestimmte Menge identischer Funktionen sicherstellen, jedoch nicht mit einer Schnittstelle.
Im Folgenden finden Sie einige Empfehlungen, die Ihnen bei der Entscheidung helfen sollen, ob Sie eine Schnittstelle oder eine abstrakte Klasse verwenden, um Polymorphismus für Ihre Komponenten bereitzustellen.
Kopiert von:
http://msdn.microsoft.com/en-us/library/scsyfw1d%28v=vs.71%29.aspx
quelle
Erwägen Sie die Verwendung abstrakter Klassen, wenn eine dieser Aussagen auf Ihre Situation zutrifft:
Erwägen Sie die Verwendung von Schnittstellen, wenn eine dieser Aussagen auf Ihre Situation zutrifft:
Quelle
quelle
Die Antworten variieren zwischen den Sprachen. In Java kann eine Klasse beispielsweise mehrere Schnittstellen implementieren (von diesen erben), aber nur von einer abstrakten Klasse erben. Schnittstellen bieten Ihnen also mehr Flexibilität. Dies gilt jedoch nicht für C ++.
quelle
Für mich würde ich in vielen Fällen mit Schnittstellen gehen. In einigen Fällen bevorzuge ich jedoch abstrakte Klassen.
Klassen in OO beziehen sich im Allgemeinen auf die Implementierung. Ich verwende abstrakte Klassen, wenn ich den untergeordneten Elementen, die ich mit Schnittstellen verwende, einige Implementierungsdetails aufzwingen möchte.
Abstrakte Klassen sind natürlich nicht nur nützlich, um die Implementierung zu erzwingen, sondern auch, um einige spezifische Details zwischen vielen verwandten Klassen auszutauschen.
quelle
Verwenden Sie eine abstrakte Klasse, wenn Sie einige grundlegende Implementierungen bereitstellen möchten.
quelle
In Java können Sie von einer (abstrakten) Klasse erben, um Funktionen bereitzustellen, und Sie können viele Schnittstellen implementieren, um die Funktionalität sicherzustellen
quelle
Rein auf der Grundlage der Vererbung würden Sie eine Zusammenfassung verwenden, in der Sie eindeutig nachkommende, abstrakte Beziehungen definieren (dh Tier-> Katze) und / oder die Vererbung von virtuellen oder nicht öffentlichen Eigenschaften, insbesondere des gemeinsam genutzten Zustands (die Schnittstellen nicht unterstützen können), erfordern ).
Sie sollten versuchen, die Komposition (über Abhängigkeitsinjektion) der Vererbung vorzuziehen, wo dies möglich ist, und beachten, dass Schnittstellen als Verträge Unit-Tests, die Trennung von Bedenken und (sprachlich variierende) Mehrfachvererbung auf eine Weise unterstützen, die Abstracts nicht können.
quelle
Ein interessanter Ort, an dem Schnittstellen besser abschneiden als abstrakte Klassen, ist, wenn Sie einer Gruppe von (verwandten oder nicht verwandten) Objekten zusätzliche Funktionen hinzufügen müssen. Wenn Sie ihnen keine abstrakte Basisklasse geben können (z. B.
sealed
wenn sie übergeordnet sind oder bereits haben), können Sie ihnen stattdessen eine Dummy-Schnittstelle (leer) geben und dann einfach Erweiterungsmethoden für diese Schnittstelle schreiben.quelle
Dies kann ein sehr schwieriger Anruf sein ...
Ein Hinweis, den ich geben kann: Ein Objekt kann viele Schnittstellen implementieren, während ein Objekt nur eine Basisklasse erben kann (in einer modernen OO-Sprache wie c # weiß ich, dass C ++ mehrere Vererbungen hat - aber ist das nicht verpönt?)
quelle
Eine abstrakte Klasse kann Implementierungen haben.
Eine Schnittstelle hat keine Implementierungen, sondern definiert lediglich eine Art Vertrag.
Es kann auch einige sprachabhängige Unterschiede geben: Beispielsweise hat C # keine Mehrfachvererbung, aber mehrere Schnittstellen können in einer Klasse implementiert werden.
quelle
Grundlegende Daumenregel lautet: Verwenden Sie für "Nomen" die abstrakte Klasse und für "Verben" die Schnittstelle
ZB:
car
ist eine abstrakte Klasse unddrive
wir können sie zu einer Schnittstelle machen.quelle
drive
Autos einbauen - das ist eine abstrakte Klasse.