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?

3voto

theschmitzer Punkte 11448

Verwenden Sie eine Basisklasse nur, wenn Sie wissen, was sie bedeutet und dass sie in diesem Fall zutrifft. Wenn sie zutrifft, verwenden Sie sie, andernfalls verwenden Sie Schnittstellen. Aber beachten Sie die Antwort über kleine Schnittstellen.

Öffentliche Vererbung wird in OOD überstrapaziert und drückt viel mehr aus, als den meisten Entwicklern bewusst ist oder sie bereit sind, sich daran zu halten. Siehe die Liskov-Substituierbarkeitsprinzip

Kurz gesagt, wenn A "ein" B ist, dann verlangt A nicht mehr als B und liefert nicht weniger als B, für jede Methode, die es offenlegt.

3voto

Wheat Punkte 827

Konzeptionell ist ein interfaz wird verwendet, um eine Reihe von Methoden, die ein Objekt zur Verfügung stellt, formal und semi-formal zu definieren. Formal bedeutet eine Reihe von Methodennamen und -signaturen, und halb-formal bedeutet eine für den Menschen lesbare Dokumentation zu diesen Methoden.

Schnittstellen sind nur Beschreibungen einer API (schließlich, API steht für Anwendungsprogrammierung interfaz ), können sie keine Implementierung enthalten, und es ist nicht möglich, eine Schnittstelle zu verwenden oder auszuführen. Sie legen lediglich den Vertrag fest, wie Sie mit einem Objekt interagieren sollen.

Klassen bieten eine Implementierung an und können erklären, dass sie keine, eine oder mehrere Schnittstellen implementieren. Wenn eine Klasse vererbt werden soll, ist es üblich, dem Klassennamen das Wort "Base" voranzustellen.

Es wird unterschieden zwischen einer Basisklasse und ein abstrakte Basisklassen (ABC). ABCs vermischen Schnittstelle und Implementierung miteinander. Abstrakt bedeutet außerhalb der Computerprogrammierung "Zusammenfassung", d.h. "abstrakt == Schnittstelle". Eine abstrakte Basisklasse kann dann sowohl eine Schnittstelle als auch eine leere, teilweise oder vollständige Implementierung beschreiben, die vererbt werden soll.

Meinungen über den Zeitpunkt der Verwendung Schnittstellen gegen abstrakte Basisklassen versus nur Klassen wird sehr unterschiedlich sein, je nachdem, was Sie entwickeln und in welcher Sprache Sie entwickeln. Schnittstellen werden oft nur mit statisch typisierten Sprachen wie Java oder C# in Verbindung gebracht, aber auch dynamisch typisierte Sprachen können über Schnittstellen y abstrakte Basisklassen . In Python zum Beispiel wird klar unterschieden zwischen einer Klasse, die angibt, dass sie implementiert eine interfaz und ein Objekt, das eine Instanz eines Klasse und gilt als anbieten. que interfaz . In einer dynamischen Sprache ist es möglich, dass zwei Objekte, die beide Instanzen desselben Klasse können erklären, dass sie vollständig verschiedene Schnittstellen. In Python ist dies nur für Objektattribute möglich, während Methoden ein gemeinsamer Zustand für alle Objekte einer Klasse . In Ruby können Objekte jedoch Methoden pro Instanz haben, so dass es möglich ist, dass die interfaz zwischen zwei Objekten desselben Klasse kann so weit variieren, wie der Programmierer es wünscht (Ruby hat jedoch keine explizite Möglichkeit, Interfaces zu deklarieren).

In dynamischen Sprachen wird die Schnittstelle zu einem Objekt oft implizit angenommen, entweder durch Introspektion eines Objekts und die Frage, welche Methoden es bietet ( Vorsicht vor dem Sprung ) oder vorzugsweise durch den einfachen Versuch, die gewünschte interfaz auf ein Objekt und das Abfangen von Ausnahmen, wenn das Objekt diese Funktion nicht bietet interfaz ( es ist einfacher, um Vergebung zu bitten als um Erlaubnis ). Dies kann zu "falsch-positiven" Ergebnissen führen, wenn zwei Schnittstellen haben denselben Methodennamen, sind aber semantisch unterschiedlich. Der Kompromiss besteht jedoch darin, dass Ihr Code flexibler ist, da Sie nicht im Voraus zu viele Angaben machen müssen, um alle möglichen Verwendungen Ihres Codes vorherzusehen.

3voto

Parappa Punkte 7356

Eine weitere Möglichkeit ist die Verwendung der "has-a"-Beziehung, auch bekannt als "ist implementiert in Form von" oder "Komposition". Manchmal ist dies eine sauberere, flexiblere Art, Dinge zu strukturieren, als die Verwendung von "is-a"-Vererbung.

Es mag logisch nicht so viel Sinn machen, zu sagen, dass Hund und Katze beide ein Haustier "haben", aber es vermeidet die üblichen Fallstricke der Mehrfachvererbung:

public class Pet
{
    void Bathe();
    void Train(Trick t);
}

public class Dog
{
    private Pet pet;

    public void Bathe() { pet.Bathe(); }
    public void Train(Trick t) { pet.Train(t); }
}

public class Cat
{
    private Pet pet;

    public void Bathe() { pet.Bathe(); }
    public void Train(Trick t) { pet.Train(t); }
}

Ja, dieses Beispiel zeigt, dass es eine Menge Code-Duplizierung und mangelnde Eleganz gibt, wenn man die Dinge auf diese Weise macht. Aber man sollte auch zu schätzen wissen, dass dies dazu beiträgt, Hund und Katze von der Klasse Pet zu entkoppeln (indem Hund und Katze keinen Zugriff auf die privaten Mitglieder von Pet haben), und es lässt Raum für Hund und Katze, von etwas anderem zu erben - möglicherweise der Klasse Mammal.

Die Zusammensetzung ist vorzuziehen, wenn kein privater Zugang erforderlich ist und Sie sich nicht auf Hund und Katze beziehen müssen, indem Sie allgemeine Verweise/Zeiger auf Haustiere verwenden. Schnittstellen bieten die Möglichkeit einer allgemeinen Referenz und können dazu beitragen, die Ausführlichkeit des Codes zu verringern, aber sie können auch die Dinge verschleiern, wenn sie schlecht organisiert sind. Vererbung ist nützlich, wenn Sie Zugriff auf private Mitglieder benötigen, und wenn Sie sie verwenden, verpflichten Sie sich zu einer starken Kopplung Ihrer Hunde- und Katzenklassen mit Ihrer Pet-Klasse, was ein hoher Preis ist.

Zwischen Vererbung, Komposition und Schnittstellen gibt es nicht den einen Weg, der immer der richtige ist, und es ist hilfreich, sich zu überlegen, wie alle drei Optionen in Harmonie genutzt werden können. Von den drei Optionen ist die Vererbung in der Regel diejenige, die am seltensten verwendet werden sollte.

2voto

Adam Hughes Punkte 11902

Ich habe festgestellt, dass ein Muster von Schnittstelle > Abstrakt > Konkret im folgenden Anwendungsfall funktioniert:

1.  You have a general interface (eg IPet)
2.  You have a implementation that is less general (eg Mammal)
3.  You have many concrete members (eg Cat, Dog, Ape)

Die abstrakte Klasse definiert gemeinsame Standardattribute der konkreten Klassen, erzwingt jedoch die Schnittstelle. Zum Beispiel:

public interface IPet{

    public boolean hasHair();

    public boolean walksUprights();

    public boolean hasNipples();
}

Da alle Säugetiere Haare und Brustwarzen haben (AFAIK, ich bin kein Zoologe), können wir dies in die abstrakte Basisklasse einbauen

public abstract class Mammal() implements IPet{

     @override
     public walksUpright(){
         throw new NotSupportedException("Walks Upright not implemented");
     }

     @override
     public hasNipples(){return true}

     @override
     public hasHair(){return true}

Und dann definieren die konkreten Klassen lediglich, dass sie aufrecht gehen.

public class Ape extends Mammal(){

    @override
    public walksUpright(return true)
}

public class Catextends Mammal(){

    @override
    public walksUpright(return false)
}

Dieses Design ist gut, wenn es viele konkrete Klassen gibt und man keine Boilerplate pflegen möchte, nur um eine Schnittstelle zu programmieren. Würden der Schnittstelle neue Methoden hinzugefügt, würden alle daraus resultierenden Klassen kaputt gehen, so dass Sie immer noch die Vorteile des Schnittstellenansatzes nutzen können.

In diesem Fall könnte das Abstraktum genauso gut konkret sein; die abstrakte Bezeichnung trägt jedoch dazu bei, die Verwendung dieses Musters hervorzuheben.

2voto

Phil C Punkte 3541

In Bezug auf C# können Schnittstellen und abstrakte Klassen in gewissem Sinne austauschbar sein. Die Unterschiede sind jedoch: i) Schnittstellen können keinen Code implementieren; ii) deshalb können Schnittstellen nicht weiter oben auf dem Stack eine Unterklasse aufrufen; und iii) nur eine abstrakte Klasse kann an eine Klasse vererbt werden, während mehrere Schnittstellen an eine Klasse implementiert werden können.

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