Menu
CoddyTech

Patrón Strategy

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

El patrón Strategy coloca cada versión de un algoritmo en su propio objeto, para que puedas cambiar el algoritmo mientras se ejecuta el programa. El objeto que lo usa, el contexto, llama a un método y no le importa qué versión contiene.

Aquí tienes dos estrategias de ataque, una clase padre y una subclase con el mismo método 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

El contexto almacena una estrategia y le delega el cálculo:

# 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 nunca comprueba qué estilo tiene. Un estilo nuevo es una clase nueva, y fighter.gd se mantiene tal como está; una cadena de if style == "heavy" dentro de attack() crecería con cada estilo.

Cuando una estrategia es una pequeña función sin datos propios, basta con un Callable. El contexto almacena la función y la ejecuta con call():

# 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

Usa clases cuando una estrategia tenga sus propios ajustes o varios métodos, y Callables para un cálculo breve. Ya has usado esta idea antes: la función de comparación que pasas a sort_custom() es una estrategia de ordenamiento.

challenge icon

Desafío

Intermedio

Un carrito de compras puede cambiar de estrategia de descuento al finalizar la compra. Discount en discount.gd es la estrategia base: sin descuento. Escribe otras dos estrategias y el carrito:

  • PercentOff (se crea con un porcentaje): apply(total) devuelve total - total * percent / 100 (aritmética entera), y label() devuelve 10% off para un 10 por ciento.
  • FixedOff (se crea con un importe): apply(total) devuelve el total menos el importe, pero nunca menos de 0, y label() devuelve 30 off para un importe de 30.
  • Cart: set_discount(new_discount) almacena la estrategia, y checkout() suma los precios y devuelve Subtotal TOTAL, LABEL, pay PRICE, donde PRICE es lo que devuelve apply() de la estrategia.

El código proporcionado lee los precios en una línea, cuántas compras se procesarán y una estrategia por línea: percent N, fixed N o none. Para los precios 50 30 40 y las estrategias percent 10, fixed 30, none, la salida es:

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

Tu código va en cart.gd, percent_off.gd y fixed_off.gd. main.gd contiene el código de entrada/salida proporcionado y no se puede editar.

Pruébalo tú mismo

extends Node

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