Menu
CoddyTech

Dekorierer-Muster

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

Das Decorator-Muster fügt einem Objekt Verhalten hinzu, indem es in ein anderes Objekt mit denselben Methoden eingeschlossen wird. Jeder Wrapper ruft das darin enthaltene Objekt auf und fügt seinen eigenen Teil hinzu, und Wrapper können in beliebiger Reihenfolge gestapelt werden.

# weapon.gd
class_name Weapon
extends RefCounted

func get_damage() -> int:
	return 10

func describe() -> String:
	return "Sword"

Ein Dekorator erweitert Weapon, sodass er überall dort eingesetzt werden kann, wo eine Waffe erwartet wird, und enthält die Waffe, die er umhüllt:

# fire_enchant.gd
class_name FireEnchant
extends Weapon

var inner: Weapon

func _init(wrapped: Weapon) -> void:
	inner = wrapped

func get_damage() -> int:
	return inner.get_damage() + 5

func describe() -> String:
	return inner.describe() + " + Fire"

SharpEnchant wird auf dieselbe Weise geschrieben, aber sein get_damage() gibt inner.get_damage() * 2 zurück und sein describe() fügt " + Sharp" hinzu.

# main.gd
var weapon: Weapon = Weapon.new()
print(weapon.describe(), ": ", weapon.get_damage())
weapon = FireEnchant.new(weapon)
weapon = SharpEnchant.new(weapon)
print(weapon.describe(), ": ", weapon.get_damage())
Sword: 10
Sword + Fire + Sharp: 30

Die Aufrufe wandern nach innen: SharpEnchant fragt FireEnchant, das wiederum das Schwert fragt. Das Schwert gibt 10 zurück, Feuer erhöht den Wert auf 15, und Schärfe verdoppelt ihn auf 30. In der anderen Reihenfolge, FireEnchant.new(SharpEnchant.new(Weapon.new())), beträgt der Schaden 10 * 2 + 5, also 25.

Ohne Decorators bräuchte jede Kombination ihre eigene Unterklasse: FireSword, SharpSword, FireSharpSword und so weiter. Mit ihnen decken zwei kleine Klassen jede Kombination ab, und eine neue Verzauberung bedeutet eine weitere Datei.

challenge icon

Aufgabe

Mittel

Ein Café stellt Getränke mit Decorators zusammen. Beverage (beverage.gd) deklariert cost() und description(); Espresso (espresso.gd, $3) und Tea (tea.gd, $2) sind bereits geschrieben. Jeder Decorator speichert das Getränk, das er umhüllt, in inner (die Konstruktoren sind bereits geschrieben). Überschreibe cost() und description() in:

  • Milk: kostet 1 mehr und fügt der Beschreibung + Milk hinzu.
  • Mocha: kostet 2 mehr und fügt + Mocha hinzu.
  • Large: verdoppelt die Kosten für alles, was sich darin befindet, und stellt der Beschreibung Large voran.

Der bereitgestellte Code liest ein, wie viele Bestellungen folgen, und dann eine Bestellung pro Zeile: das Getränk (espresso oder tea) und seine Extras, die von links nach rechts angewendet werden. Für espresso milk large und tea mocha milk lautet die Ausgabe:

Large Espresso + Milk: $8
Tea + Mocha + Milk: $5

Dein Code gehört in milk.gd, mocha.gd und large.gd. main.gd enthält den bereitgestellten Ein-/Ausgabecode und kann nicht bearbeitet werden.

Probier es selbst

extends Node

func _ready():
	# Vorgegebener Eingabe-/Ausgabecode: unverändert lassen
	var count := int(OS.read_string_from_stdin())
	for i in count:
		var words := OS.read_string_from_stdin().split(" ")
		var drink: Beverage = Tea.new()
		if words[0] == "espresso":
			drink = Espresso.new()
		for extra in words.slice(1):
			match extra:
				"milk":
					drink = Milk.new(drink)
				"mocha":
					drink = Mocha.new(drink)
				"large":
					drink = Large.new(drink)
		print("%s: $%d" % [drink.description(), drink.cost()])
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