Menu
CoddyTech

Komposition vs. Vererbung

Teil des Abschnitts Objektorientierte Programmierung der GDScript-Journey von Coddy. Lektion 40 von 65.

Klassen verwenden Code auf zwei Arten wieder. Vererbung (extends) bedeutet, dass eine Klasse eine Art einer anderen Klasse ist: Ein Mage ist ein Player. Komposition bedeutet, dass eine Klasse einen Bestandteil hat: Sie speichert ein anderes Objekt in einer Member-Variable und überträgt die Arbeit an dieses:

# motor.gd
class_name Motor
extends RefCounted

func start() -> String:
	return "motor running"

# car.gd
class_name Car
extends RefCounted

var motor := Motor.new()

func start() -> String:
	return "Car starts, " + motor.start()

Car.new().start() gibt Car starts, motor running zurück. Das Auto weiß nicht, wie ein Motor funktioniert: Es ruft motor.start() auf. Einen Aufruf wie diesen an einen Bestandteil weiterzugeben, nennt man Delegation. (Die Klasse heißt Motor, weil Engine bereits eine Godot-Klasse ist.)

Komposition zahlt sich aus, wenn sich Teile ändern oder kombinieren. Bei Vererbung sind eine gehende Figur und eine fliegende Figur zwei Unterklassen, und eine Fledermaus, die zu fliegen beginnt, kann ihre Klasse nicht ändern. Bei Komposition hat die Figur ein Bewegungsteil, und es auszutauschen, ist eine einzige Zuweisung:

# character.gd
class_name Character
extends RefCounted

var char_name: String
var movement: Movement

func _init(new_name: String, new_movement: Movement) -> void:
	char_name = new_name
	movement = new_movement

func move() -> String:
	return char_name + " " + movement.move()

# main.gd
var bat := Character.new("Bat", Walk.new())
print(bat.move()) # Bat läuft
bat.movement = Fly.new()
print(bat.move()) # Bat fliegt

Hier erweitern Walk und Fly eine kleine Movement-Klasse: Die beiden Techniken funktionieren zusammen. Eine GDScript-Klasse kann nur eine Klasse extend, daher erhält ein Objekt durch Komposition ebenfalls mehrere Fähigkeiten, indem es mehrere Bestandteile enthält.

Verwende Vererbung für eine echte „ist ein“-Beziehung, die sich niemals ändert. Verwende Komposition, wenn die Klasse etwas „hat“ oder wenn der Teil während des Spiels ausgetauscht werden muss.

challenge icon

Aufgabe

Einfach

Ein Ritter erbt nicht von einer Waffe: Ein Ritter hat eine Waffe und kann sie wechseln. Erstelle beide Klassen.

  • Weapon speichert weapon_name und damage, die beide vom Konstruktor festgelegt werden: Weapon.new("Sword", 7).
  • Knight speichert knight_name (aus dem Konstruktor) und eine Waffe, die anfangs null ist.
  • equip(new_weapon) ersetzt die Waffe und drop() setzt sie wieder auf null.
  • attack() gibt Ada attacks with Sword for 7 damage zurück, wobei der Name des Ritters sowie der Name und der Schaden der Waffe verwendet werden, oder Ada has no weapon, wenn keine vorhanden ist.

Der bereitgestellte Code liest den Namen des Ritters und die Anzahl der folgenden Befehle (equip Sword 7, drop, attack) ein und führt sie aus. Für Ada und attack, equip Sword 7, attack, equip Axe 12, attack, drop, attack gibt er Folgendes aus:

Ada has no weapon
Equipped Sword
Ada attacks with Sword for 7 damage
Equipped Axe
Ada attacks with Axe for 12 damage
Dropped the weapon
Ada has no weapon

Dein Code gehört in weapon.gd und knight.gd. main.gd enthält den bereitgestellten Ein-/Ausgabecode und kann nicht bearbeitet werden.

Probier es selbst

extends Node

func _ready():
	# Vorgegebener Ein-/Ausgabecode: unverändert lassen
	var knight := Knight.new(OS.read_string_from_stdin())
	var count := int(OS.read_string_from_stdin())
	for i in count:
		var parts := OS.read_string_from_stdin().split(" ")
		if parts[0] == "equip":
			knight.equip(Weapon.new(parts[1], int(parts[2])))
			print("Equipped ", parts[1])
		elif parts[0] == "drop":
			knight.drop()
			print("Dropped the weapon")
		else:
			print(knight.attack())
quiz iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Objektorientierte Programmierung

Übe selbstständig: Online-GDScript-Compiler