Menu
CoddyTech

Pattern Decorator

Fa parte della sezione Programmazione orientata agli oggetti del percorso GDScript di Coddy. Lezione 52 di 65.

Il pattern Decorator aggiunge comportamento a un oggetto racchiudendolo in un altro oggetto con gli stessi metodi. Ogni wrapper chiama l'oggetto al suo interno e aggiunge la propria parte, e i wrapper possono essere impilati in qualsiasi ordine.

# weapon.gd
class_name Weapon
extends RefCounted

func get_damage() -> int:
	return 10

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

Un decoratore estende Weapon, quindi può essere usato ovunque sia previsto un'arma e contiene l'arma che avvolge:

# 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 è scritto allo stesso modo, ma il suo get_damage() restituisce inner.get_damage() * 2 e il suo describe() aggiunge " + Sharp".

# 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

Le chiamate procedono verso l'interno: SharpEnchant interroga FireEnchant, che interroga la spada. La spada restituisce 10, il fuoco lo porta a 15 e l'incantesimo affilato lo raddoppia a 30. Nell'altro ordine, FireEnchant.new(SharpEnchant.new(Weapon.new())), il danno è 10 * 2 + 5, cioè 25.

Senza i decoratori, ogni combinazione richiederebbe una propria sottoclasse: FireSword, SharpSword, FireSharpSword e così via. Con essi, due piccole classi coprono ogni combinazione, e un nuovo incantesimo richiede un altro file.

challenge icon

Sfida

Medio

Una caffetteria prepara bevande con i decorator. Beverage (beverage.gd) dichiara cost() e description(); sono già scritte Espresso (espresso.gd, $3) e Tea (tea.gd, $2). Ogni decorator memorizza in inner la bevanda che avvolge (i costruttori sono già scritti). Esegui l’override di cost() e description() in:

  • Milk: costa 1 in più e aggiunge + Milk alla descrizione.
  • Mocha: costa 2 in più e aggiunge + Mocha.
  • Large: raddoppia il costo di tutto ciò che contiene e mette Large all’inizio della descrizione.

Il codice fornito legge il numero di ordini successivi, poi un ordine per riga: la bevanda (espresso o tea) e i suoi extra, applicati da sinistra a destra. Per espresso milk large e tea mocha milk l’output è:

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

Il tuo codice va in milk.gd, mocha.gd e large.gd. main.gd contiene il codice di input/output fornito e non può essere modificato.

Provalo tu

extends Node

func _ready():
	# Codice di input/output fornito: lascialo così com'è
	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 iconMettiti alla prova

Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.

Tutte le lezioni di Programmazione orientata agli oggetti

Esercitati da solo: Compilatore GDScript online