Frage

Für mein neues Pet-Projekt habe ich eine Frage zum Design, die bereits entschieden ist, aber ich möchte auch noch ein paar andere Meinungen dazu.

Ich habe zwei Klassen (vereinfacht):

class MyObject
{
  string name {get;set;}
  enum relation {get;set;}
  int value {get;set;}
}

class MyObjectGroup
{
  string name {get;set;}
  enum relation {get;set;}
  int value {get;set;}
  List<MyObject> myobjects {get;set;}
}

Später im Projekt MyObjectGroup Und MyObject sollten gleichermaßen genutzt werden.Dafür könnte ich zwei Wege gehen:

  • Erstellen Sie eine Schnittstelle: IObject
  • Erstellen Sie eine abstrakte Klasse: ObjectBase

Ich habe mich für den Weg der Schnittstelle entschieden, den ich später nicht in Code schreiben muss ObjectBase jedes Mal aber IObject Nur der Einfachheit halber – aber welche weiteren positiven Aspekte hat dieser Weg?

Und zweitens, wie wäre es mit dem Hinzufügen? IXmlSerializable zur ganzen Geschichte?Lassen Sie die Schnittstelle erben IXmlSerializable Oder hat es noch mehr positive Aspekte, die es umzusetzen gilt? IXmlSerializable in der abstrakten Basisklasse?

War es hilfreich?

Lösung

Generell ist der Ansatz, den ich in dieser Situation verwenden ist sowohl eine Schnittstelle und eine abstrakte Klasse zu haben. Die Schnittstellen definiert, gut, die Schnittstelle. Die abstrakte Klasse ist nur ein Helfer.

Sie können wirklich nicht mit diesem Ansatz schief gehen. Schnittstellen bietet die Flexibilität, die Umsetzung zu ändern. Abstrakte Klassen geben Sie Text und Helfer Code, den Sie nicht zu verwenden sind gezwungen, die Sie sonst wäre es, wenn Ihre Methoden explizit im Sinne einer abstrakten Klasse definiert wurden.

Andere Tipps

Dies sind nur einige der Unterschiede zwischen den Schnittstellen und abstrakten Klassen.

1A. Es kann eine Klasse erben (Implementieren) eine oder mehrere Schnittstellen. Also in C # werden Schnittstellen verwendet Mehrfachvererbung zu erreichen.
1B. Eine Klasse kann nur eine abstrakte Klasse erben.

2A. Ein Schnittstelle beliebigen Code nicht zur Verfügung stellen kann, nur die Unterschrift.
2B. Eine abstrakte Klasse kann komplett zur Verfügung stellt, Standard-Code und / oder nur die Details, die überschrieben werden müssen.

3A. Eine Schnittstelle kann nicht Zugriffsmodifikatoren für das U-Boote, Funktionen, Eigenschaften usw. alles hat als öffentlich angenommen.
3B. Eine abstrakte Klasse kann Zugriffsmodifikatoren für die U-Boote, Funktionen, Eigenschaften enthalten.

4A. Schnittstellen verwendet, um die peripheren Fähigkeiten einer Klasse zu definieren. Für zB. Ein Ship und ein Car können einen IMovable-Schnittstelle implementieren.
4B. Eine abstrakte Klasse, die den Kern Identität einer Klasse definiert, und es wird für Objekte verwendet wird.

5A. Wenn verschiedene Implementierungen nur Aktien Methodensignaturen dann ist es besser, Schnittstellen zu verwenden.
5B. Wenn verschiedene Implementierungen der gleichen Art sind und gemeinsames Verhalten oder Status verwenden dann abstrakte Klasse ist besser zu nutzen.

6A. Wenn wir eine neue Methode für eine Schnittstelle hinzufügen, dann müssen wir alle Implementierungen der Schnittstelle aufzuspüren und Implementierung für die neue Methode zu definieren.
6B. Wenn wir eine neue Methode zu einer abstrakten Klasse hinzufügen, dann haben wir die Möglichkeit, Standardimplementierung bereitstellt und damit alle bestehenden Code könnte funktionieren.

7A. Eine Schnittstelle kann nicht über Felder definiert.
7B. Eine abstrakte Klasse kann haben Felder und Konstanten definiert.

8A. Eine Schnittstelle kann nicht Konstruktor haben.
8B. Eine abstrakte Klasse Standardkonstruktoren implementiert haben kann.

9A. Eine Schnittstelle kann nur von anderen Schnittstellen erben.
9B. Eine abstrakte Klasse von Schnittstellen, abstrakter Klasse erben kann, oder auch Klasse.

Die Schnittstelle würde mein Standard sein, bis es eine ist Grund eine Basisklasse zu verwenden, da es weniger Entscheidungen für uns macht.

würde ich nicht IXmlSerializable beinhalten, es sei denn ich aber musste; es ist eine schmutzige, knifflige Schnittstelle, die oft eine Ursache des Leidens ist.

Was genau sind Ihre Serialisierungsanforderungen? Möglicherweise gibt es bessere Optionen ... aber für viele Serializer eine Basisklasse würde einfacher sein als eine Schnittstelle. Zum Beispiel für XmlSerializer könnten Sie haben:

[XmlInclude(typeof(MyObject))] // : ObjectBase 
[XmlInclude(typeof(MyObjectGroup))] // : ObjectBase 
public abstract class ObjectBase { /*  */ }

(die genaue Vorgehensweise hängt von dem Serializer)

Im Allgemeinen sollten Sie berücksichtigen Schnittstellen wie Verträge , dass einige Arten implementieren und abstrakte Klassen wie Knoten in Vererbungshierarchie , die von ihnen selbst nicht vorhanden sind (dh es ist ein < em> „ist eine“ Beziehung zwischen der abgeleiteten Klasse und der Basis abstrakten Klasse). Doch in der Praxis, müssen Sie Schnittstellen in anderen Fällen verwenden, wie wenn man die Mehrfachvererbung benötigen.

Zum Beispiel ist IXmlSerializable keine „Einheit“ von selbst aus. Es definiert einen Vertrag, der ein Unternehmen umsetzen kann. Schnittstellen leben „außerhalb“ der Vererbungshierarchie.

Eine Schnittstelle ermöglicht es Ihnen, einen ‚Vertrag‘ zu definieren, dass das Objekt durch die Bereitstellung von Eigenschaften und Methoden erfüllen müssen wie die Schnittstelle beschrieben. Sie können durch die Variablen der Schnittstelle-Typ auf Objekte beziehen, die eine gewisse Verwirrung, was dazu führen kann genau angeboten wird.

Eine Basisklasse bietet die Möglichkeit, eine Erbschaft ‚Baum‘ zu bauen, wo komplexere Klassen (einen gemeinsamen ‚Typen‘) auf den Fundamenten einer einfachere ‚Basis‘ Klassen gebaut werden. Das klassische und ärgerlich Beispiel in OO ist in der Regel eine Basisklasse von ‚Shape‘ und der von Dreieck, Quadrat vererbt, etc.

Der wichtigste Punkt ist, dass Sie mit einer Schnittstelle müssen den gesamten Vertrag mit jeder Klasse schaffen, das es, mit einer Vererbungsbaum (Basisklassen) implementiert Sie nur Ändern / Hinzufügen von Eigenschaften und Methoden, die für das Kind Klasse einzigartig sind , gemeinsame Eigenschaften und Methoden bleiben in der Basisklasse.

In Ihrem Beispiel oben ich das Objekt ‚MyObjectGroup‘ haben würde die Basis ‚MyObject‘ Klasse erbt, nichts von einer Schnittstelle hier gewonnen werden, dass ich sehen kann.

Beim Entwerfen von Klassen hat der Architekt zwei Dinge im Kopf.

  1. Verhalten eines Objekts.
  2. Objektimplementierung.

Wenn eine Entität über mehr als eine Implementierung verfügt, ist die Trennung des Verhaltens eines Objekts von seiner Implementierung einer der Schlüssel zur Wartbarkeit und Entkopplung.Die Trennung kann entweder durch die abstrakte Klasse oder die Schnittstelle erreicht werden, aber welche ist die beste?Nehmen wir ein Beispiel, um dies zu überprüfen.

Nehmen wir ein Entwicklungsszenario, in dem sich Dinge (Anfrage, Klassenmodell usw.) sehr häufig ändern und Sie bestimmte Versionen der Anwendung bereitstellen müssen.

Erste Problemstellung :Sie müssen eine „Train“-Klasse für die indische Eisenbahn erstellen, die 1970 das Verhalten „maxSpeed“ hat.

1.Geschäftsmodellierung mit abstraktem Unterricht

V 0.0 (Anfangsproblem)Erste Problemstellung:Sie müssen eine erstellen Train Klasse für die indische Eisenbahn, die 1970 das Verhalten maxSpeed ​​hatte.

public abstract class Train {
    public int maxSpeed();
}

V 1.0 (Geändertes Problem 1)geänderte Problemstellung:Sie müssen eine erstellen Diesel Train Klasse für die indische Eisenbahn mit dem Verhalten maxSpeed ​​im Jahr 1975.

public abstract class DieselTrain extends train {
     public int maxFuelCapacity ();
}

V 2.0 (Geändertes Problem 2)chanted Problemstellung:Sie müssen eine erstellen ElectricalTrain Klasse für die indische Eisenbahn, die 1980 das Verhalten maxSpeed ​​und maxVoltage hatte.

public abstract class ElectricalTrain extends train {
     public int maxvoltage ();
}

V 3.0 (Geändertes Problem 3)

chanted Problemstellung:Sie müssen eine erstellen HybridTrain (verwendet sowohl Diesel als auch Elektrizität) Klasse für indische Eisenbahnen, die 1985 das Verhalten maxSpeed, maxVoltage, maxVoltage aufwies.

public abstract class HybridTrain extends ElectricalTrain , DisealTrain {
    { Not possible in java }
}
{here Business modeling with abstract class fails}

2.Geschäftsmodellierung mit Schnittstelle

Nur ändern abstract Wort zu interface Und… Ihre Geschäftsmodellierung mit der Schnittstelle wird erfolgreich sein.

http://javaqna.wordpress.com/2008/08/24/why-the-use-on-interfaces-instead-of-abstract-classes-is-encouraged-in-java-programming/

Schnittstelle: Wenn Ihre untergeordneten Klassen alle eine bestimmte Gruppe von Methoden/Funktionalitäten implementieren sollen, es aber jeder untergeordneten Klasse freisteht, ihre eigene Implementierung bereitzustellen, verwenden Sie Schnittstellen.

Für z.B.Wenn Sie eine Klassenhierarchie für Fahrzeuge implementieren, implementieren Sie eine Schnittstelle namens Vehicle, die Eigenschaften wie Color MaxSpeed ​​usw. hat.und Methoden wie Drive().Alle Kinderkurse wie Auto, Roller, Flugzeug, SolarAuto usw.sollte von dieser Basisschnittstelle abgeleitet sein, aber eine separate Implementierung der von Vehicle bereitgestellten Methoden und Eigenschaften bereitstellen.

–> Wenn Sie möchten, dass Ihre untergeordneten Klassen mehrere unabhängige Funktionen in kurzen Mehrfachvererbungsschnittstellen implementieren.

Für z.B.Wenn Sie eine Klasse namens „SpaceShip“ implementieren, die sowohl über die Funktionen eines Fahrzeugs als auch über die eines UFO verfügen muss, erstellen Sie sowohl „Vehicle“ als auch „UFO“ als Schnittstellen und erstellen Sie dann eine Klasse „SpaceShip“, die sowohl „Vehicle“ als auch „UFO“ implementiert.

Abstrakte Klassen:

–> Wenn Sie eine Anforderung haben, bei der Ihre Basisklasse die Standardimplementierung bestimmter Methoden bereitstellen soll, während andere Methoden von untergeordneten Klassen überschrieben werden können, verwenden Sie abstrakte Klassen.

Für z.B.Nehmen Sie noch einmal das Beispiel der Fahrzeugklasse oben.Wenn wir möchten, dass alle von Vehicle abgeleiteten Klassen die Drive()-Methode auf feste Weise implementieren, während die anderen Methoden von untergeordneten Klassen überschrieben werden können.In einem solchen Szenario implementieren wir die Fahrzeugklasse als abstrakte Klasse mit einer Implementierung von Drive, während wir die anderen Methoden/Eigenschaften abstrakt belassen, damit sie von untergeordneten Klassen überschrieben werden können.

–> Der Zweck einer abstrakten Klasse besteht darin, eine gemeinsame Definition einer Basisklasse bereitzustellen, die mehrere abgeleitete Klassen gemeinsam nutzen können.

Beispielsweise kann eine Klassenbibliothek eine abstrakte Klasse definieren, die als Parameter für viele ihrer Funktionen verwendet wird, und Programmierer, die diese Bibliothek verwenden, müssen ihre eigene Implementierung der Klasse bereitstellen, indem sie eine abgeleitete Klasse erstellen.

Sie könnte tatsächlich mit beiden gehen. Objectbase erspart Ihnen die Mühe der Umsetzung der gemeinsamen Eigenschaften mehr als einmal und implementiert IObject für Sie. Überall verwenden Sie es IObject beziehen, so dass Sie Tests mit Mocks tun können später

ich eher für die Basis abstrakte Klasse gehen würde, weil theoretisch (na ja, es ist nur eine Theorie, ich bin nicht zu beweisen oder zu sagen, dass jede andere schlimmer, dann ist dies) - Schnittstellen zu verwenden, wenn Sie zeigen möchten, , dass ein Objekt etwas dazu in der Lage ist (wie IComparable - zeigen Sie, dass, was auch immer es implementiert, kann auf etwas anderes verglichen werden), während, wenn Sie zwei Instanzen haben, die nur etwas gemeinsam oder 1 logischen Elternteil - abstrakte Klassen verwendet werden sollen, .
Sie könnten auch für beide Ansätze gehen, Basisklasse verwenden, das wird eine Schnittstelle implementieren, die explizit darauf hinweisen wird, was Ihre Klasse tun können.

Unter sonst gleichen Bedingungen, mit der Schnittstelle gehen. Einfacher für Unit-Tests zu verspotten.

Aber im Allgemeinen alles, was ich Basisklassen verwenden, um, wenn es gibt einig gemeinsamen Code, den ich eher an einer Stelle setzen würde, anstatt jede Instanz der abgeleiteten Klasse. Wenn es etwas wie das, was Sie beschreiben, wo die Art, wie sie es gewohnt sind die gleiche, aber die zugrunde liegende Mechanik unterschiedlich ist, eine Schnittstelle geeignetere klingt.

Ich habe mit abstrakten Klassen in meinen Projekten, aber in zukünftigen Projekten, werde ich Schnittstellen verwenden. Der Vorteil von „Mehrfachvererbung“ ist äußerst nützlich. Mit der Fähigkeit, eine völlig neue Implementierung der Klasse zu schaffen, sowohl im Code oder zu Testzwecken, ist immer willkommen. Schließlich, wenn in der Zukunft möchten Sie die Möglichkeit haben, den Code von externen Entwicklern zu gestalten, müssen Sie sie nicht Ihren echten Code geben - sie können nur die Schnittstellen verwenden ...

Wenn Sie Funktion in der Klasse haben, sollten Sie abstrakte Klasse verwenden statt Schnittstelle. Im Allgemeinen wird eine Schnittstelle zu sein im Namen eines Typs verwendet wird.

Beachten Sie, dass Sie nicht Operatoren in Schnittstellen außer Kraft setzen können. Das ist das einzige wirkliche Problem mit ihnen, so weit es mich betrifft.

Die Wahl Schnittstellen und abstrakte Klassen ist kein entweder / oder Satz. Wenn Sie Ihr Design ändern müssen, macht es zu einer Schnittstelle. Sie können jedoch abstrakte Klassen, die einige Standardverhalten bieten. Abstrakte Klassen sind ausgezeichnete Kandidaten innerhalb von Anwendungs-Frameworks.

Abstrakte Klassen können Sie einige Verhaltensweisen definieren; sie zwingen Ihre Subklassen anderen zur Verfügung zu stellen. Zum Beispiel, wenn Sie einen Anwendungs-Framework haben, kann eine abstrakte Klasse Standarddienste wie Ereignis und Nachrichtenbehandlung zur Verfügung stellen. Diese Dienste ermöglichen die Anwendung auf Ihre Bewerbung Rahmen steck. Es gibt jedoch einige anwendungsspezifische Funktionalität, die nur Ihre Anwendung ausführen kann. Eine solche Funktionalität kann Aufgaben Starten und Herunterfahren gehören, die oft anwendungsabhängig sind. Also anstatt zu versuchen, dieses Verhalten selbst, die abstrakte Basisklasse zu definieren, kann abstrakte Shutdown und Startup-Methoden deklariert. Die Basisklasse weiß, dass es diese Methoden braucht, sondern eine abstrakte Klasse können Sie Ihre Klasse zugeben, dass es nicht weiß, wie diese Aktionen durchzuführen; er weiß nur, dass er die Aktionen einleiten müssen. Wenn es Zeit ist, zu starten, kann die abstrakte Klasse die Startmethode aufrufen. Wenn die Basisklasse diese Methode aufruft, Java ruft die Methode durch die Kindklasse definiert.

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

Die Definition der abstrakten Klasse kann Code und Zustand beschreibt, und Klassen, die von ihnen abgeleitet werden können von anderen Klassen zur gleichen Zeit nicht ableiten. Das ist, was der technische Unterschied ist.

Daher ist aus der Sicht der Nutzung und Philosophie, ist der Unterschied, dass eine abstrakte Klasse durch die Einrichtung, Sie irgendeine andere Funktionalität beschränken, dass die Objekte dieser Klasse implementieren können, und diese Objekte mit einiger grundlegenden Funktionalität bereitzustellen, ist gemeinsam für eine solche Aufgabe (das ist eine Art von Einschränkung ist, auch), während sie durch eine Schnittstelle einrichten, stellen Sie keine Einschränkungen für andere Funktionalität und keine Echt Code vorsorgen für die Funktionalität, die Sie im Sinn haben. Verwenden Sie die abstrakte Klassen, wenn Sie wissen alles, was Objekte dieser Klasse sollen zum Vorteil ihrer Nutzer zu tun. Verwenden Sie die Schnittstellen, wenn die Objekte auch tun könnte etwas anderes, dass Sie nicht einmal jetzt erraten kann.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top