2010-03-03 13 views
8

Nun, ich wollte fragen, was der Unterschied ist, aber es wurde schon beantwortet. Aber jetzt frage ich, warum haben sie diese Unterschiede gemacht? (Ich spreche über Java hier, ich weiß nicht, ob das gleiche für andere Sprachen gilt)Warum abstrakte Klassen und Interfaces erstellen?

Die beiden Dinge scheinen sehr ähnlich. Abstrakte Klassen können einen Methodenkörper definieren, während Interfaces dies nicht können, aber mehrere Interfaces vererbt werden können. Warum also haben sie nicht (durch "sie" meine ich Sun, als sie Java schrieben) eine Sache gemacht, wo man einen Methodenkörper schreiben kann und Dieser Typ kann mehr als einmal von einer Klasse vererbt werden.

Gibt es einen Vorteil darin, dass ich nicht in der Lage bin, einen Methodenkörper zu schreiben oder mehrere Male zu verlängern, die ich nicht sehe?

Antwort

10

Da es zulässt, dass Klassen mehrere Implementierungen für dieselbe Methodensignatur erben, führt das zu der offensichtlichen Frage, welche zur Laufzeit verwendet werden sollte.

Java vermeidet dies, indem mehrere Vererbungen nur für Schnittstellen unterstützt werden. Die in jeder Schnittstelle deklarierten Signaturen können viel einfacher kombiniert werden (Java verwendet grundsätzlich die Vereinigung aller Methoden)

+0

Ah, ich wusste, dass da etwas sein muss, was ich vermisst habe, das macht Sinn! – Paul

3

Mehrfache Vererbung ist in einer Sprache (Compiler wirklich) schwieriger zu implementieren, da es zu bestimmten Problemen führen kann. Diese Probleme wurden bereits zuvor diskutiert: What is the exact problem with multiple inheritance.

Ich habe immer angenommen, dass dies ein Kompromiss in Java war. Schnittstellen ermöglichen es einer Klasse, mehrere Verträge zu erfüllen, ohne dass die mehrfache Vererbung Probleme bereitet.

0

Der andere Ansatz, den Sie beschreiben, ist der Ansatz von C++ (Mixins zum Beispiel). Die Probleme im Zusammenhang mit einer solchen "Mehrfachvererbung" sind ziemlich komplex und haben in C++ mehrere Kritiker.

+0

C++ hat keine Mixins, wie ich sie verstehe. Mixins können zur Laufzeit zu einer Klasse hinzugefügt werden ("Logger-Verhalten zu dieser DBI-Instanz hinzufügen"), das kein Kern der C++ - Sprache ist. –

+0

@Philip Ich weiß nicht, was du meinst. Mixins werden häufig in C++ verwendet, vielleicht am bekanntesten in Grady Boochs Büchern. –

+0

Ich denke, wir sind nur nicht einig über die Definition von "Mixin" dann. Keine große Sache, mach weiter. –

5

Mehrfache Vererbung in C++ führt zu semantischen Ambiguitäten wie diamond inheritance problem. MI ist ziemlich mächtig, hat aber komplexe Konsequenzen.

Durch die Spezialisierung der Schnittstellen erhöht sich auch die Sichtbarkeit des Konzepts, um die Komplexität von Informationen zu verbergen und zu reduzieren. In C++ ist das Definieren reiner abstrakter Grundlagen ein Zeichen für einen ausgereiften Programmierer. In Java begegnen Sie ihnen zu einem viel früheren Zeitpunkt in der Entwicklung eines Programmierers.

1

Sie zu machen, ist der Weg, den die Scala-Leute mit Traits eingeschlagen haben, eine Schnittstelle, die Methoden haben und mehrfache Vererbung unterstützen kann.

Ich denke, Schnittstellen sind für mich sauber, da sie nur Anforderungen angeben (Design by Contract), während abstrakte Klassen gemeinsames Verhalten definieren (Implementierung), also ein anderes Werkzeug für einen anderen Job? Schnittstellen erlauben wahrscheinlich auch eine effizientere Codegenerierung während der Kompilierzeit?

0

Vererbung bedeutet, dass Sie die Natur (Bedeutung) und Verantwortung (Verhalten) der übergeordneten Klasse erben, während Schnittstellen-Implementierung bedeutet, dass Sie einen Vertrag erfüllen (zB Serializable), die nichts mit dem Kern der Natur zu tun haben oder Verantwortung der Klasse.

Abstrakte Klasse lässt Sie eine Natur definieren, die Sie generisch und nicht direkt Instanziable sein möchten, weil es spezialisiert sein muss. Sie wissen, wie Sie einige Aufgaben auf hoher Ebene ausführen (z. B. eine Entscheidung gemäß einigen Parametern treffen), aber Sie kennen die Details für einige untergeordnete Aktionen nicht (z. B. einige intermediäre Parameter berechnen), da dies von Implementierungsentscheidungen abhängt.Eine Alternative zur Lösung dieses Problems ist die Strategy design pattern. Es ist flexibler, erlaubt Laufzeit-Strategie-Wechsel und Null-Verhalten, ist aber komplexer (und Laufzeit-Swatching ist nicht immer notwendig). Darüber hinaus können Sie einige Bedeutung & Schreibanlagen verlieren (Polymorphie & Typ-Überprüfung wird ein bisschen härter, weil die Strategie eine Komponente ist, nicht das Objekt selbst).

Zusammenfassung class = is-a, Strategie = hat-eine

Edit: wie für Mehrfachvererbung, siehe Pontus Gagge Antwort.

2

dieses Beispiel vor:

public abstract class Engine 
{ 
    public abstract void switchPowerOn(); 
    public abstract void sprinkleSomeFuel(); 
    public abstract void ignite(); 

    public final void start() 
    { 
    switchPowerOn(); 
    sprinkleSomeFuel(); 
    ignite(); 
    } 
} 

Abstrakte Klasse kann Ihnen helfen, mit soliden Basis Methoden, die können oder nicht außer Kraft gesetzt werden kann, aber in diesen Verfahren verwendet es abstrakt methos Ihnen die Möglichkeit zu bieten, spezifische, was zu tun . In meinem Beispiel haben verschiedene Motoren unterschiedliche Implementierungen, wie sie den Strom einschalten, etwas Kraftstoff für die Zündung streuen und die Zündung machen, aber die Startsequenz des Motors bleibt immer dieselbe.

Dieses Muster nennt sich "Form Template Method" und ist ehrlich gesagt die einzig sinnvolle Verwendung von abstrakten Klassen in Java für mich.

Verwandte Themen