840 Stimmen

Schnittstelle vs. Basisklasse

Wann sollte ich eine Schnittstelle und wann eine Basisklasse verwenden?

Sollte es immer eine Schnittstelle sein, wenn ich keine Basisimplementierung der Methoden definieren möchte?

Wenn ich eine Hunde- und Katzenklasse habe. Warum sollte ich IPet anstelle von PetBase implementieren wollen? Ich kann verstehen, mit Schnittstellen für ISheds oder IBarks (IMakesNoise?), weil diese auf ein Haustier von Haustier Basis platziert werden können, aber ich verstehe nicht, welche für eine allgemeine Pet verwenden.

11 Stimmen

Nur ein Punkt, den Sie meiner Meinung nach berücksichtigen sollten - Schnittstellen können verschiedene Einschränkungen mit sich bringen, derer Sie sich möglicherweise erst in sehr späten Phasen bewusst sind. Zum Beispiel mit .NET können Sie nicht serialisieren eine Schnittstelle Mitglied Variable, so dass, wenn Sie eine Klasse Zoo und ein Mitglied Variable Array von IAnimals haben Sie nicht in der Lage, Zoo serialisieren (und das bedeutet, schreiben WebServices oder andere Dinge, die eine Serialisierung wäre ein Schmerz).

2 Stimmen

Diese Frage könnte helfen, das Konzept der Schnittstellen zu verstehen. stackoverflow.com/q/8531292/1055241

0 Stimmen

Ich bin nur neugierig. Ich traf in der CLR über C# den folgenden Auszug: I tend to prefer using the interface technique over the base type technique because the base type technique doesn’t allow the developer to choose the base type that works best in a particular situation. . Ich kann nicht begreifen, was in dem Auszug gemeint ist. Wir können einige Basistypen erstellen und für jeden von ihnen einen abgeleiteten Typ erstellen, so dass ein Entwickler einen Basistyp auswählen kann. Könnte mir bitte jemand erklären, was ich übersehe? Ich glaube, es kann ein Teil dieser Frage sein. Oder sollte ich eine andere Frage zu dem spezifischen Auszug stellen?

62voto

Kilhoffer Punkte 31599

Im Allgemeinen sollten Sie Schnittstellen gegenüber abstrakten Klassen bevorzugen. Ein Grund, eine abstrakte Klasse zu verwenden, ist, wenn Sie eine gemeinsame Implementierung zwischen konkreten Klassen haben. Natürlich sollten Sie trotzdem eine Schnittstelle (IPet) deklarieren und eine abstrakte Klasse (PetBase) diese Schnittstelle implementieren lassen. Schnittstellen ermöglichen ein Höchstmaß an Flexibilität und Portabilität von Typen über Grenzen hinweg. Bei der Übergabe von Referenzen über Grenzen hinweg sollte immer die Schnittstelle und nicht der konkrete Typ übergeben werden. Dies ermöglicht es dem Empfänger, die konkrete Implementierung zu bestimmen und bietet maximale Flexibilität. Dies gilt ganz besonders für die Programmierung nach TDD/BDD.

Die Gang of Four schreibt in ihrem Buch: "Da die Vererbung eine Unterklasse den Details der Implementierung ihrer Elternklasse aussetzt, wird oft gesagt, dass die Vererbung die Kapselung aufhebt. Ich glaube, dass dies wahr ist.

0 Stimmen

Igitt. Ich persönlich glaube, dass dies völlig rückständig ist. Schnittstellen sollten das absolute Minimum an Funktionalität für einen Typ enthalten, und Basisklassen sollten ein reichhaltiges Gerüst bieten, auf dem Anpassungen aufgebaut werden können. Wenn man das in eine Schnittstelle packt, macht man es sehr schwer zu implementieren.

1 Stimmen

Niemand hat gesagt, dass Ihre Schnittstellen riesig sein müssen. Kleinere, mehrere Schnittstellen und reichhaltigere Basisklassen ergeben eine großartige API.

3 Stimmen

Geht es nur mir so, oder haben die meisten "Common Worker"-Klassen eine gemeinsame Implementierung? In diesem Zusammenhang verstößt es gegen Ihre allgemeine Regel, Schnittstellen zu bevorzugen. Ich würde Ihre Verallgemeinerung in 2 Verallgemeinerungen umformulieren: Die allgemeinen Klassen, die keine oder nur wenig Logik enthalten, sollten eine Schnittstelle implementieren. Diejenigen allgemeinen Klassen, die eine "anständige" Menge an Logik enthalten, sollten von einer Basisklasse abgeleitet werden (da sie höchstwahrscheinlich die gleiche Funktionalität haben).

52voto

fryguybob Punkte 4280

Dies ist ziemlich .NET-spezifisch, aber das Buch Framework Design Guidelines argumentiert, dass Klassen im Allgemeinen mehr Flexibilität in einem sich entwickelnden Framework bieten. Sobald eine Schnittstelle ausgeliefert wird, hat man keine Chance mehr, sie zu ändern, ohne den Code, der diese Schnittstelle verwendet, zu zerstören. Bei einer Klasse hingegen kann man sie ändern, ohne den Code, der mit ihr verknüpft ist, zu zerstören. Solange man die richtigen Änderungen vornimmt, wozu auch das Hinzufügen neuer Funktionen gehört, kann man seinen Code erweitern und weiterentwickeln.

Krzysztof Cwalina sagt auf Seite 81:

Im Laufe der drei Versionen von .NET Framework habe ich mit vielen Entwicklern in unserem Team über diese Richtlinie gesprochen. Viele von ihnen, auch diejenigen, die anfangs nicht mit den Richtlinien einverstanden waren, haben gesagt, dass sie es bedauern, eine API als Schnittstelle ausgeliefert zu haben. Mir ist kein einziger Fall bekannt, in dem es jemand bereut hätte, eine Klasse ausgeliefert zu haben.

Dennoch gibt es sicherlich einen Platz für Schnittstellen. Als allgemeine Richtlinie sollte immer eine abstrakte Basisklassen-Implementierung einer Schnittstelle bereitgestellt werden, wenn auch nur als Beispiel dafür, wie die Schnittstelle implementiert werden kann. Im besten Fall spart diese Basisklasse eine Menge Arbeit.

0 Stimmen

Fand dies, als ich mich auf die Suche machte, um zu verstehen, warum diese Seite learn.microsoft.com/de-us/dotnet/standard/library-guidance/ rät, abstrakte Basisklassen über Schnittstellen zu nutzen (nicht sicher, ob diese Empfehlung auf der Seite für jedes Paket im Allgemeinen gilt)

20voto

Flory Punkte 2811

Juan,

Ich betrachte Schnittstellen gerne als eine Möglichkeit, eine Klasse zu charakterisieren. Eine bestimmte Hunderassenklasse, z. B. ein YorkshireTerrier, kann von der übergeordneten Hundeklasse abstammen, aber sie implementiert auch IFurry, IStubby und IYippieDog. Die Klasse definiert also, was die Klasse ist, aber die Schnittstelle sagt uns etwas über sie.

Das hat den Vorteil, dass ich zum Beispiel alle IYippieDogs sammeln und in meine Ocean-Sammlung aufnehmen kann. Jetzt kann ich also eine bestimmte Menge von Objekten durchsuchen und diejenigen finden, die die gewünschten Kriterien erfüllen, ohne die Klasse zu genau untersuchen zu müssen.

Ich finde, dass Schnittstellen wirklich nur eine Teilmenge des öffentlichen Verhaltens einer Klasse definieren sollten. Wenn sie das gesamte öffentliche Verhalten für alle Klassen definiert, die sie implementieren, dann braucht sie normalerweise nicht zu existieren. Sie sagen mir nichts Nützliches.

Dieser Gedanke widerspricht jedoch der Idee, dass jede Klasse eine Schnittstelle haben sollte und man für die Schnittstelle programmieren sollte. Das ist in Ordnung, aber am Ende hat man eine Menge eins-zu-eins-Schnittstellen zu Klassen und das macht die Dinge verwirrend. Ich verstehe, dass der Gedanke dahinter ist, dass es nicht wirklich etwas kostet und dass man jetzt Dinge mit Leichtigkeit ein- und austauschen kann. Ich stelle jedoch fest, dass ich das nur selten tue. Meistens ändere ich nur die bestehende Klasse und habe genau die gleichen Probleme wie immer, wenn die öffentliche Schnittstelle der Klasse geändert werden muss, nur dass ich sie jetzt an zwei Stellen ändern muss.

Wenn Sie also wie ich denken, würden Sie definitiv sagen, dass Katze und Hund IPettable sind. Es ist eine Charakterisierung, die zu beiden passt.

Der andere Teil der Frage ist jedoch, ob sie dieselbe Basisklasse haben sollten. Die Frage ist, ob sie im Großen und Ganzen als dieselbe Sache behandelt werden müssen. Sicherlich sind sie beide Tiere, aber passt das zu der Art und Weise, wie wir sie zusammen verwenden werden?

Angenommen, ich möchte alle Tierklassen sammeln und sie in meinen Arche-Container legen.

Oder müssen es Säugetiere sein? Vielleicht brauchen wir eine Art tierübergreifende Melkfabrik?

Müssen sie überhaupt miteinander verbunden werden? Reicht es aus, wenn man weiß, dass sie beide IPettable sind?

Ich verspüre oft den Wunsch, eine ganze Klassenhierarchie abzuleiten, obwohl ich eigentlich nur eine Klasse brauche. Ich tue das in der Erwartung, dass ich es eines Tages brauchen könnte, und normalerweise ist das nicht der Fall. Und selbst wenn ich es brauche, muss ich in der Regel eine Menge tun, um das Problem zu lösen. Das liegt daran, dass die erste Klasse, die ich erstelle, nicht der Hund ist, so viel Glück habe ich nicht, es ist stattdessen das Schnabeltier. Jetzt basiert meine gesamte Klassenhierarchie auf dem bizarren Fall und ich habe eine Menge verschwendeten Code.

Vielleicht stellen Sie auch irgendwann fest, dass nicht alle Katzen IPett-fähig sind (wie die haarlose Katze). Jetzt können Sie diese Schnittstelle auf alle abgeleiteten Klassen übertragen, die passen. Sie werden feststellen, dass es eine viel weniger einschneidende Änderung ist, dass Cats plötzlich nicht mehr von PettableBase abgeleitet sind.

19voto

RWendi Punkte 1416

Hier ist die grundlegende und einfache Definition von Schnittstelle und Basisklasse:

  • Basisklasse = Objektvererbung.
  • Schnittstelle = funktionale Vererbung.

Prost

15voto

Richard Harrison Punkte 18867

Sie wird in diesem Artikel gut erklärt Java World Artikel .

Ich persönlich neige dazu, Schnittstellen zu verwenden, um Interfaces zu definieren - d.h. Teile des Systemdesigns, die festlegen, wie auf etwas zugegriffen werden soll.

Es ist nicht ungewöhnlich, dass ich eine Klasse habe, die eine oder mehrere Schnittstellen implementiert.

Abstrakte Klassen verwende ich als Grundlage für etwas anderes.

Der folgende Text ist ein Auszug aus dem oben genannten Artikel JavaWorld.com Artikel, Autor Tony Sintes, 20.04.01


Schnittstelle vs. abstrakte Klasse

Die Wahl zwischen Schnittstellen und abstrakten Klassen ist keine Entweder-Oder-Antwort. Wenn Sie Ihren Entwurf ändern müssen, machen Sie eine Schnittstelle daraus. Sie können jedoch abstrakte Klassen haben, die ein bestimmtes Standardverhalten bieten. Abstrakte Klassen sind hervorragende Kandidaten für Anwendungsframeworks.

Mit abstrakten Klassen können Sie einige Verhaltensweisen definieren; sie zwingen Ihre Unterklassen dazu, andere bereitzustellen. Wenn Sie z. B. ein Anwendungs-Framework haben, kann eine abstrakte Klasse Standarddienste wie Ereignis- und Nachrichtenbehandlung bereitstellen. Diese Dienste ermöglichen es Ihrer Anwendung, sich in Ihr Anwendungsframework einzufügen. Es gibt jedoch einige anwendungsspezifische Funktionen, die nur Ihre Anwendung ausführen kann. Dazu gehören beispielsweise Aufgaben beim Starten und Herunterfahren, die oft anwendungsabhängig sind. Anstatt also zu versuchen, dieses Verhalten selbst zu definieren, kann die abstrakte Basisklasse abstrakte Methoden für das Herunterfahren und Starten deklarieren. Die Basisklasse weiß, dass sie diese Methoden benötigt, aber eine abstrakte Klasse lässt Ihre Klasse zugeben, dass sie nicht weiß, wie sie diese Aktionen ausführen soll; sie weiß nur, dass sie die Aktionen initiieren muss. Wenn es an der Zeit ist, den Rechner zu starten, kann die abstrakte Klasse die Startup-Methode aufrufen. Wenn die Basisklasse diese Methode aufruft, ruft Java die von der Unterklasse definierte Methode auf.

Viele Entwickler vergessen, dass eine Klasse, die eine abstrakte Methode definiert, diese Methode auch aufrufen kann. Abstrakte Klassen sind eine hervorragende Möglichkeit, geplante Vererbungshierarchien zu erstellen. Sie sind auch eine gute Wahl für Nicht-Blatt-Klassen in Klassenhierarchien.

Klasse vs. Schnittstelle

Einige sagen, dass man alle Klassen in Form von Schnittstellen definieren sollte, aber ich denke, dass diese Empfehlung ein bisschen extrem ist. Ich verwende Schnittstellen, wenn ich sehe, dass sich etwas in meinem Entwurf häufig ändern wird.

Mit dem Strategiemuster können Sie beispielsweise neue Algorithmen und Prozesse in Ihr Programm einfügen, ohne die Objekte zu ändern, die sie verwenden. Ein Mediaplayer weiß vielleicht, wie man CDs, MP3s und wav-Dateien abspielt. Natürlich möchten Sie diese Wiedergabealgorithmen nicht fest in den Player einprogrammieren; das würde das Hinzufügen eines neuen Formats wie AVI erschweren. Darüber hinaus wird Ihr Code mit nutzlosen Case-Anweisungen übersät sein. Und zu allem Überfluss müssen Sie diese Case-Anweisungen jedes Mal aktualisieren, wenn Sie einen neuen Algorithmus hinzufügen. Alles in allem ist dies keine sehr objektorientierte Art zu programmieren.

Mit dem Strategiemuster können Sie den Algorithmus einfach hinter einem Objekt kapseln. Wenn Sie das tun, können Sie jederzeit neue Medien-Plug-ins bereitstellen. Nennen wir die Plug-in-Klasse MediaStrategy. Dieses Objekt würde eine Methode haben: playStream(Stream s). Um also einen neuen Algorithmus hinzuzufügen, erweitern wir einfach unsere Algorithmusklasse. Wenn das Programm nun auf den neuen Medientyp stößt, delegiert es einfach die Wiedergabe des Streams an unsere Medienstrategie. Natürlich benötigen Sie einige Funktionen, um die benötigten Algorithmus-Strategien richtig zu instanzieren.

Dies ist ein ausgezeichneter Ort, um eine Schnittstelle zu verwenden. Wir haben das Strategy-Muster verwendet, das eindeutig auf eine Stelle im Entwurf hinweist, die sich ändern wird. Daher sollten Sie die Strategie als Schnittstelle definieren. Im Allgemeinen sollten Sie Schnittstellen gegenüber der Vererbung bevorzugen, wenn Sie wollen, dass ein Objekt einen bestimmten Typ hat, in diesem Fall MediaStrategy. Sich bei der Typidentität auf die Vererbung zu verlassen, ist gefährlich, da Sie dadurch in einer bestimmten Vererbungshierarchie gefangen sind. Java lässt keine Mehrfachvererbung zu, so dass Sie nicht etwas erweitern können, das Ihnen eine nützliche Implementierung oder mehr Typidentität bietet.

2 Stimmen

+1. "Sich auf die Vererbung für die Typidentität zu verlassen, ist gefährlich; es sperrt Sie in eine bestimmte Vererbungshierarchie ein." Dieser Satz beschreibt perfekt meine Gründe für die Bevorzugung von Schnittstellen.

0 Stimmen

Und darüber hinaus, anstatt zu erweitern, komponieren Sie die Implementierung hinter jeder Methode Ihrer Schnittstelle.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X