Menu
CoddyTech
flag Ar iconالعربيةdown icon

نمط Strategy

جزء من قسم البرمجة كائنية التوجّه في رحلة GDScript على Coddy. الدرس 49 من 65.

يضع نمط Strategy كل إصدار من الخوارزمية في كائن مستقل، بحيث يمكنك تبديل الخوارزمية أثناء تشغيل البرنامج. يستدعي الكائن الذي يستخدمها، أي السياق، طريقة واحدة ولا يهتم بالإصدار الذي يحتفظ به.

إليك استراتيجيتا هجوم، وفئة أب وفئة فرعية لهما الطريقة نفسها 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

يخزّن السياق استراتيجيةً ويُسند إليها عملية الحساب:

# 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 أبدًا من النمط الذي يستخدمه. كل نمط جديد يعني صنفًا جديدًا، ويظل fighter.gd كما هو؛ أما سلسلة if style == "heavy" داخل attack() فستطول مع كل نمط جديد.

عندما تكون الاستراتيجية دالة صغيرة واحدة لا تملك بيانات خاصة بها، يكون استخدام Callable كافيًا. يخزّن السياق الدالة ويشغّلها باستخدام 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

استخدم الأصناف عندما تكون للاستراتيجية إعداداتها الخاصة أو عدة أساليب، واستخدم العناصر القابلة للاستدعاء لإجراء عملية حسابية قصيرة واحدة. لقد استخدمت هذه الفكرة من قبل: دالة المقارنة التي تمررها إلى sort_custom() هي استراتيجية للفرز.

challenge icon

التحدي

متوسط

يمكن لسلة التسوق تبديل استراتيجيات الخصم عند الدفع. Discount في discount.gd هي الاستراتيجية الأساسية: بلا خصم. اكتب استراتيجيتين أخريين والسلة:

  • PercentOff (تُنشأ باستخدام نسبة مئوية): تُرجع apply(total) القيمة total - total * percent / 100 (حساب بالأعداد الصحيحة)، وتُرجع label() القيمة 10% off عند نسبة 10 بالمئة.
  • FixedOff (تُنشأ باستخدام مبلغ): تُرجع apply(total) المجموع مطروحًا منه المبلغ، لكن لا تقل النتيجة أبدًا عن 0، وتُرجع label() القيمة 30 off عند مبلغ 30.
  • Cart: تخزّن set_discount(new_discount) الاستراتيجية، وتجمع checkout() الأسعار وتُرجع Subtotal TOTAL, LABEL, pay PRICE، حيث إن PRICE هو ما تُرجعه apply() للاستراتيجية.

يقرأ الكود المرفق الأسعار في سطر واحد، وعدد عمليات الدفع التالية، واستراتيجية واحدة في كل سطر: percent N أو fixed N أو none. بالنسبة إلى الأسعار 50 30 40 والاستراتيجيات percent 10 وfixed 30 وnone، يكون الناتج:

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

ضع كودك في cart.gd وpercent_off.gd وfixed_off.gd. يحتوي main.gd على كود الإدخال/الإخراج المرفق ولا يمكن تعديله.

جرّب بنفسك

extends Node

func _ready():
	# كود الإدخال/الإخراج المقدَّم: اتركه كما هو
	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 iconاختبر نفسك

يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.

جميع دروس البرمجة كائنية التوجّه

تدرّب بنفسك: مترجم GDScript عبر الإنترنت