Menu
CoddyTech

Patrón Decorator

Parte de la sección Programación orientada a objetos del Journey de GDScript de Coddy. Lección 52 de 65.

El patrón Decorator añade comportamiento a un objeto envolviéndolo en otro objeto con los mismos métodos. Cada envoltorio llama al objeto que contiene y añade su propia parte, y los envoltorios pueden apilarse en cualquier orden.

# weapon.gd
class_name Weapon
extends RefCounted

func get_damage() -> int:
	return 10

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

Un decorador extiende Weapon, así que puede ocupar el lugar de cualquier arma y contiene el arma que envuelve:

# 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 se escribe de la misma manera, pero su método get_damage() devuelve inner.get_damage() * 2 y su método describe() añade " + 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

Las llamadas avanzan hacia dentro: SharpEnchant consulta a FireEnchant, que consulta a la espada. La espada devuelve 10, el fuego lo convierte en 15 y el afilado lo duplica hasta 30. En el otro orden, FireEnchant.new(SharpEnchant.new(Weapon.new())), el daño es 10 * 2 + 5, que es 25.

Sin decoradores, cada combinación necesitaría su propia subclase: FireSword, SharpSword, FireSharpSword y así sucesivamente. Con ellos, dos clases pequeñas cubren todas las combinaciones, y un nuevo encantamiento requiere un archivo más.

challenge icon

Desafío

Intermedio

Una cafetería prepara bebidas con decoradores. Beverage (beverage.gd) declara cost() y description(); ya están escritos Espresso (espresso.gd, $3) y Tea (tea.gd, $2). Cada decorador almacena en inner la bebida que envuelve (los constructores ya están escritos). Sobrescribe cost() y description() en:

  • Milk: cuesta 1 más y añade + Milk a la descripción.
  • Mocha: cuesta 2 más y añade + Mocha.
  • Large: duplica el costo de todo lo que contiene y coloca Large al principio de la descripción.

El código proporcionado lee cuántos pedidos vienen a continuación y luego un pedido por línea: la bebida (espresso o tea) y sus extras, aplicados de izquierda a derecha. Para espresso milk large y tea mocha milk, la salida es:

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

Tu código va en milk.gd, mocha.gd y large.gd. main.gd contiene el código proporcionado de entrada/salida y no se puede editar.

Pruébalo tú mismo

extends Node

func _ready():
	# Código de entrada/salida proporcionado: mantenlo tal como está
	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 iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Programación orientada a objetos

Practica por tu cuenta: Compilador de GDScript online