Methoden überschreiben
Ein Endgegner erbt beschreibe von Monster, beschreibt sich also wie jedes Monster: Drache (300 Leben). Aber ein Endgegner sollte auch sagen, in welcher Phase er ist. Eine abgeleitete Klasse kann ihre eigene Version einer Methode ihrer Elternklasse schreiben. Das heißt, die Methode zu überschreiben (englisch override):
class Monster {
name: string;
leben: number;
constructor(name: string, leben: number) {
this.name = name;
this.leben = leben;
}
beschreibe(): string {
return `${this.name} (${this.leben} Leben)`;
}
}
class Endgegner extends Monster {
phase: number = 1;
override beschreibe(): string {
return `${super.beschreibe()}, Phase ${this.phase}`;
}
}
const gegner: Monster[] = [new Monster("Goblin", 30), new Endgegner("Drache", 300)];
for (const monster of gegner) {
console.log(monster.beschreibe());
}Das gibt aus:
Goblin (30 Leben)
Drache (300 Leben), Phase 1Hier sind drei Dinge neu:
- Die Methode in
Endgegnerhat denselben Namen wie die inMonster, ersetzt also für einen Endgegner die geerbte. Welche Version läuft, hängt vom Objekt ab, nicht vom Typ der Variablen: In der Schleife istmonsterfür TypeScript einMonster, aber das zweite Objekt ist ein Endgegner, also läuft seine eigene Methodebeschreibe. super.beschreibe()ruft die Version der Elternklasse auf. Der Endgegner muss nicht wiederholen, wie sich Monster beschreiben: Er nimmt diesen Text und fügt die Phase hinzu. (Vorsicht:this.beschreibe()würde die eigene Methode des Endgegners aufrufen, die sich immer wieder selbst aufrufen würde, bis das Programm mitRangeError: Maximum call stack size exceededanhält.)- Das Schlüsselwort
overridesagt: „Diese Methode ersetzt eine Methode der Elternklasse.“ Es ist optional, aber so kann TypeScript dich prüfen.
Warum override hilft. Ohne es ersetzt ein Tippfehler im Namen nichts; er fügt nur eine neue Methode hinzu:
class Monster {
name: string;
leben: number;
constructor(name: string, leben: number) {
this.name = name;
this.leben = leben;
}
beschreibe(): string {
return `${this.name} (${this.leben} Leben)`;
}
}
class Endgegner extends Monster {
phase: number = 1;
bechreibe(): string {
return `${this.name} (${this.leben} Leben), Phase ${this.phase}`;
}
}
const gegner: Monster[] = [new Monster("Goblin", 30), new Endgegner("Drache", 300)];
for (const monster of gegner) {
console.log(monster.beschreibe());
}Das gibt aus:
Goblin (30 Leben)
Drache (300 Leben)Die Methode des Endgegners wird nie aufgerufen, und nichts sagt dir, warum. Schreibe override bechreibe(): string, und TypeScript findet den Fehler:
main.ts(18,14): error TS4117: This member cannot have an 'override' modifier because it is not declared in the base class 'Monster'. Did you mean 'beschreibe'?Eine überschreibende Methode muss auch zu der der Elternklasse passen: Sie muss mit denselben Argumenten funktionieren und einen Wert des Typs zurückgeben, den die Methode der Elternklasse zurückgibt. Würde beschreibe des Endgegners eine Zahl zurückgeben, meldete TypeScript Property 'beschreibe' in type 'Endgegner' is not assignable to the same property in base type 'Monster'. (TS2416). Deshalb kann ein Endgegner überall für ein Monster einspringen: Alles, was du mit einem Monster tun kannst, funktioniert auch mit einem Endgegner.
So schreibst du es:
Anweisungen
- 1
Der Drache soll sich mit seiner Feuerkraft beschreiben, aber das Programm gibt nur
Roter Drache (280 Leben)aus. Schreibeoverridevor die Methode des Drachen. TypeScript findet dann den Fehler; behebe ihn, sodass das Programm Folgendes ausgibt:Goblin (10 Leben) Roter Drache (280 Leben), Feuer 40 - 2
Die Methode des Drachen wiederholt, wie sich Monster beschreiben. Verwende stattdessen
super.beschreibe()für diesen Teil. Das Programm gibt dasselbe aus. - 3
Drachen haben dicke Schuppen: Sie erleiden nur den halben Schaden. Überschreibe
nimmSchadeninDrache(mitoverride), sodass die Methode die Version der Elternklasse mit der halben Menge aufruft. Das Programm gibt aus:Goblin (10 Leben) Roter Drache (290 Leben), Feuer 40