Menu
CoddyTech

Strategie-Muster

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

Das Strategy-Muster legt jede Version eines Algorithmus in ein eigenes Objekt, sodass du den Algorithmus austauschen kannst, während das Programm läuft. Das Objekt, das ihn verwendet, der Kontext, ruft eine Methode auf und kümmert sich nicht darum, welche Version es enthält.

Hier sind zwei Angriffsstrategien: eine Elternklasse und eine Unterklasse mit derselben Methode damage():

# attack_style.gd
class_name AttackStyle
extends RefCounted

func damage(power: int) -> int:
	return power
# heavy_attack.gd
class_name HeavyAttack
extends AttackStyle

func damage(power: int) -> int:
	return power * 2

Der Kontext speichert eine Strategie und überlässt ihr die Berechnung:

# fighter.gd
class_name Fighter
extends RefCounted

var power := 10
var style: AttackStyle = AttackStyle.new()

func set_style(new_style: AttackStyle) -> void:
	style = new_style

func attack() -> void:
	print("Hit for ", style.damage(power))
# main.gd
var fighter := Fighter.new()
fighter.attack()
fighter.set_style(HeavyAttack.new())
fighter.attack()
Hit for 10
Hit for 20

Fighter prüft nie, welchen Stil es verwendet. Ein neuer Stil ist eine neue Klasse, und fighter.gd bleibt unverändert; eine if style == "heavy"-Kette innerhalb von attack() würde mit jedem Stil länger werden.

Wenn eine Strategie eine kleine Funktion ohne eigene Daten ist, reicht ein Callable aus. Der Kontext speichert die Funktion und führt sie mit call() aus:

# price_calculator.gd
class_name PriceCalculator
extends RefCounted

var discount: Callable = func(price): return price

func final_price(price: int) -> int:
	return discount.call(price)
# main.gd
var calc := PriceCalculator.new()
print(calc.final_price(80))
calc.discount = func(price): return price / 2
print(calc.final_price(80))
calc.discount = func(price): return max(price - 25, 0)
print(calc.final_price(80))
80
40
55

Verwende Klassen, wenn eine Strategie eigene Einstellungen oder mehrere Methoden hat, und Callables für eine kurze Berechnung. Du hast diese Idee bereits verwendet: Die Vergleichsfunktion, die du an sort_custom() übergibst, ist eine Sortierstrategie.

challenge icon

Aufgabe

Mittel

Ein Warenkorb kann beim Bezahlen zwischen Rabattstrategien wechseln. Discount in discount.gd ist die Basisstrategie: kein Rabatt. Schreibe zwei weitere Strategien und den Warenkorb:

  • PercentOff (wird mit einem Prozentsatz erstellt): apply(total) gibt total - total * percent / 100 zurück (Ganzzahlarithmetik), und label() gibt bei 10 Prozent 10% off zurück.
  • FixedOff (wird mit einem Betrag erstellt): apply(total) gibt den Gesamtbetrag abzüglich des Betrags zurück, jedoch niemals weniger als 0, und label() gibt bei einem Betrag von 30 30 off zurück.
  • Cart: set_discount(new_discount) speichert die Strategie, und checkout() addiert die Preise und gibt Subtotal TOTAL, LABEL, pay PRICE zurück, wobei PRICE dem von apply() der Strategie zurückgegebenen Wert entspricht.

Der bereitgestellte Code liest die Preise in einer Zeile, die Anzahl der folgenden Bezahlvorgänge und eine Strategie pro Zeile ein: percent N, fixed N oder none. Für die Preise 50 30 40 und die Strategien percent 10, fixed 30, none lautet die Ausgabe:

Subtotal 120, 10% off, pay 108
Subtotal 120, 30 off, pay 90
Subtotal 120, no discount, pay 120

Dein Code gehört in cart.gd, percent_off.gd und fixed_off.gd. main.gd enthält den bereitgestellten Ein-/Ausgabecode und darf nicht bearbeitet werden.

Probier es selbst

extends Node

func _ready():
	# Vorgegebener Ein-/Ausgabecode: unverändert lassen
	var cart := Cart.new()
	for price in OS.read_string_from_stdin().split(" "):
		cart.add_item(int(price))
	var count := int(OS.read_string_from_stdin())
	for i in count:
		var parts := OS.read_string_from_stdin().split(" ")
		if parts[0] == "percent":
			cart.set_discount(PercentOff.new(int(parts[1])))
		elif parts[0] == "fixed":
			cart.set_discount(FixedOff.new(int(parts[1])))
		else:
			cart.set_discount(Discount.new())
		print(cart.checkout())
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