Angenommen, ich habe eine reine abstrakte Klasse (dh eine abstrakte Klasse ohne Implementierung):
abstract class A {
abstract m(): void;
}
Wie in C # und Java, kann ich verlängern die abstrakte Klasse:
class B extends A {
m(): void { }
}
Aber anders als in C # und Java kann ich auch die abstrakte Klasse implementieren :
class C implements A {
m(): void { }
}
Wie unterscheiden sich Klassen B
und C
Verhaltensweisen? Warum sollte ich eins gegen das andere wählen?
(Derzeit decken das TypeScript- Handbuch und die Sprachspezifikation keine abstrakten Klassen ab.)
typescript
abstract-class
extends
implements
Michael Liu
quelle
quelle
abstract
, dass in TS verfügbar war, und dies half mir, es zu verstehen.class C implements A
. Ich wusste nicht einmal, dass es möglich ist, bis ich diese Beiträge gelesen habe, und ich war in letzter Zeit viel in den ts-Dokumenten .Antworten:
Das Schlüsselwort implements behandelt die Klasse A als Schnittstelle, dh C muss alle in A definierten Methoden implementieren , unabhängig davon, ob sie in A implementiert sind oder nicht . Auch gibt es keine Anrufe zu Super Methoden in C .
Erweitert verhält sich eher so, wie Sie es vom Keyword erwarten würden. Sie müssen nur die abstrakten Methoden implementieren, und Superaufrufe sind verfügbar / generiert.
Ich denke, dass es bei abstrakten Methoden keinen Unterschied macht. Sie haben jedoch selten eine Klasse mit nur abstrakten Methoden. Wenn Sie dies tun, ist es viel besser, sie einfach in eine Schnittstelle umzuwandeln .
Sie können dies leicht sehen, indem Sie sich den generierten Code ansehen. Ich habe einen Spielplatz Beispiel hier .
quelle
A
es sich um eine reine abstrakte Klasse handelt, ist der einzige beobachtbare Unterschied möglicherweise das Verhalten desinstanceof
Schlüsselworts? Ich stimme zu, dass Schnittstellen wahrscheinlich reinen abstrakten Klassen vorzuziehen wären. In Angular 2 kann jedoch nur letzteres als DI-Provider-Token verwendet werden.Ich wurde hierher geführt, weil ich mir gerade die gleiche Frage gestellt hatte, und als ich die Antworten las, wurde mir klar, dass die Wahl auch den
instanceof
Bediener betrifft .Da eine abstrakte Klasse ein tatsächlicher Wert ist, der an JS ausgegeben wird, kann sie zur Laufzeitprüfung verwendet werden, wenn eine Unterklasse sie erweitert.
abstract class A {} class B extends A {} class C implements A {} console.log(new B() instanceof A) // true console.log(new C() instanceof A) // false
quelle
Aufbauend auf @ toskv Antwort , wenn Sie erweitern eine abstrakte Klasse, müssen Sie rufen
super()
in der Konstruktor der Unterklasse. Wenn Sie die abstrakte Klasse implementieren , müssen Sie nicht aufrufensuper()
(aber Sie müssen alle in der abstrakten Klasse deklarierten Methoden implementieren, einschließlich privater Methoden).Das Implementieren einer abstrakten Klasse anstelle einer Erweiterung kann hilfreich sein, wenn Sie eine Scheinklasse zum Testen erstellen möchten, ohne sich um die Abhängigkeiten und den Konstruktor der ursprünglichen Klasse kümmern zu müssen.
quelle
Im Beispiel der von Ihnen angegebenen Erweiterungen fügen Sie der Klasse nichts Neues hinzu. Es wird also um nichts erweitert. Obwohl es gültig ist, um nichts zu erweitern, scheint mir Typescript in diesem Fall "Geräte" angemessener zu sein. Aber am Ende des Tages sind sie gleichwertig.
quelle