Menu
CoddyTech

Patron Strategy

Fait partie de la section Programmation orientée objet du Journey GDScript de Coddy. Leçon 49 sur 65.

Le patron Strategy place chaque version d’un algorithme dans son propre objet, afin que tu puisses remplacer l’algorithme pendant l’exécution du programme. L’objet qui l’utilise, le contexte, appelle une méthode et ne se soucie pas de la version qu’il contient.

Voici deux stratégies d’attaque, une classe parent et une sous-classe avec la même méthode 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

Le contexte stocke une stratégie et lui délègue le calcul :

# 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 ne vérifie jamais quel style il possède. Un nouveau style correspond à une nouvelle classe, et fighter.gd reste tel quel ; une chaîne if style == "heavy" dans attack() s’allongerait avec chaque style.

Lorsqu’une stratégie est une petite fonction sans données qui lui sont propres, un Callable suffit. Le contexte stocke la fonction et l’exécute avec 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

Utilisez des classes lorsqu’une stratégie a ses propres paramètres ou plusieurs méthodes, et des Callables pour un calcul court. Vous avez déjà utilisé cette idée : la fonction de comparaison que vous transmettez à sort_custom() est une stratégie de tri.

challenge icon

Défi

Moyen

Un panier peut changer de stratégie de remise au moment du paiement. Discount dans discount.gd est la stratégie de base : aucune remise. Écris-en deux autres ainsi que le panier :

  • PercentOff (créée avec un pourcentage) : apply(total) renvoie total - total * percent / 100 (arithmétique entière), et label() renvoie 10% off pour 10 pour cent.
  • FixedOff (créée avec un montant) : apply(total) renvoie le total moins le montant, sans jamais descendre sous 0, et label() renvoie 30 off pour un montant de 30.
  • Cart : set_discount(new_discount) enregistre la stratégie, et checkout() additionne les prix et renvoie Subtotal TOTAL, LABEL, pay PRICE, où PRICE est la valeur renvoyée par apply() de la stratégie.

Le code fourni lit les prix sur une ligne, le nombre de paiements qui suivent, puis une stratégie par ligne : percent N, fixed N ou none. Pour les prix 50 30 40 et les stratégies percent 10, fixed 30, none, la sortie est :

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

Ton code va dans cart.gd, percent_off.gd et fixed_off.gd. main.gd contient le code fourni pour les entrées/sorties et ne peut pas être modifié.

Essayez vous-même

extends Node

func _ready():
	# Code d'entrée/sortie fourni : conservez-le tel quel
	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 iconTestez-vous

Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.

Toutes les leçons de Programmation orientée objet

Entraînez-vous par vous-même : Compilateur GDScript en ligne