Menu
Coddy logo textTech
flag Ar iconالعربيةdown icon

نمط Strategy

جزء من قسم Object Oriented Programming في رحلة Python على Coddy — الدرس 48 من 64.

يُعرف نمط الاستراتيجية (Strategy Pattern) عائلة من الخوارزميات، ويغلف كل واحدة منها، ويجعلها قابلة للتبديل. يمكنك تبديل الخوارزميات في وقت التشغيل دون تغيير كود العميل.

إليك فئات استراتيجية بسيطة لطرق دفع مختلفة:

class CreditCard:
    def pay(self, amount):
        return f"Paid ${amount} with Credit Card"

class PayPal:
    def pay(self, amount):
        return f"Paid ${amount} with PayPal"

class Bitcoin:
    def pay(self, amount):
        return f"Paid ${amount} with Bitcoin"

كل استراتيجية تنفذ نفس الطريقة (pay) ولكن بسلوك مختلف.

قم بإنشاء فئة سياق (context class) تستخدم الاستراتيجيات:

class ShoppingCart:
    def __init__(self):
        self.total = 0
        self.payment_strategy = None
    
    def add_item(self, price):
        self.total += price
    
    def set_payment_strategy(self, strategy):
        self.payment_strategy = strategy
    
    def checkout(self):
        return self.payment_strategy.pay(self.total)

يمكن لفئة السياق (context class) التبديل بين استراتيجيات الدفع المختلفة.

استخدم نمط الاستراتيجية (Strategy pattern):

cart = ShoppingCart()
cart.add_item(50)
cart.add_item(30)

# استخدام استراتيجية بطاقة الائتمان
cart.set_payment_strategy(CreditCard())
print(cart.checkout())

# التبديل إلى استراتيجية PayPal
cart.set_payment_strategy(PayPal())
print(cart.checkout())

أنشئ مثالاً آخر باستخدام استراتيجيات الفرز:

class BubbleSort:
    def sort(self, data):
        return f"Bubble sorted: {sorted(data)}"

class QuickSort:
    def sort(self, data):
        return f"Quick sorted: {sorted(data)}"

class Sorter:
    def __init__(self, strategy):
        self.strategy = strategy
    
    def set_strategy(self, strategy):
        self.strategy = strategy
    
    def sort_data(self, data):
        return self.strategy.sort(data)

# استخدم استراتيجيات فرز مختلفة
numbers = [3, 1, 4, 1, 5]

sorter = Sorter(BubbleSort())
print(sorter.sort_data(numbers))

sorter.set_strategy(QuickSort())
print(sorter.sort_data(numbers))

المخرجات:

Paid $80 with Credit Card
Paid $80 with PayPal
Bubble sorted: [1, 1, 3, 4, 5]
Quick sorted: [1, 1, 3, 4, 5]

نقطة رئيسية: يتيح لك نمط الاستراتيجية (Strategy Pattern) تبديل الخوارزميات في وقت التشغيل. قم بتعريف استراتيجيات مختلفة بنفس الواجهة (interface)، ثم اترك فئة السياق (context class) تختار أي واحدة ستستخدم. هذا يجعل كودك مرناً وسهل التوسيع بخوارزميات جديدة دون تغيير الكود الحالي.

challenge icon

التحدي

متوسط

قم بتنفيذ استراتيجية BitcoinPayment جديدة لنظام التسوق الخاص بنا.

مهمتك هي:

  1. إنشاء فئة BitcoinPayment التي تنفذ PaymentStrategy
    • يجب أن تقبل wallet_address في المنشئ (constructor)
    • يجب أن تطبع طريقة pay بالضبط: Paying $X using Bitcoin wallet: Y حيث X هو المبلغ و Y هو عنوان المحفظة
    • يجب أن تعيد طريقة pay القيمة True بعد الطباعة
  2. كتابة دالة main تقوم بما يلي:
    • إنشاء عربة تسوق (shopping cart)
    • إضافة كمبيوتر محمول (laptop) بتكلفة $1200 وسماعات رأس (headphones) بتكلفة $100 إلى العربة
    • إنشاء BitcoinPayment مع عنوان المحفظة "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa"
    • تعيين استراتيجية الدفع هذه على العربة
    • استدعاء طريقة checkout

يتضمن كود البداية بالفعل if __name__ == "__main__": في الأسفل — لست بحاجة لإضافتها بنفسك. هذا عرف في لغة Python يضمن أن دالة main() الخاصة بك تعمل فقط عند تنفيذ الملف مباشرة (وليس عند استيراده بواسطة وحدة أخرى). ببساطة قم بتعريف دالة main() وسيقوم المربع البرمجي المقدم باستدعائها تلقائياً.

اتبع نفس الهيكل الموضح في أمثلة الدرس.

ورقة مرجعية

يحدد نمط الاستراتيجية (Strategy Pattern) عائلة من الخوارزميات، ويقوم بتغليف كل منها، ويجعلها قابلة للتبديل. يمكنك تبديل الخوارزميات في وقت التشغيل دون تغيير كود العميل.

قم بإنشاء فئات استراتيجية (strategy classes) بنفس الواجهة:

class CreditCard:
    def pay(self, amount):
        return f"Paid ${amount} with Credit Card"

class PayPal:
    def pay(self, amount):
        return f"Paid ${amount} with PayPal"

class Bitcoin:
    def pay(self, amount):
        return f"Paid ${amount} with Bitcoin"

قم بإنشاء فئة سياق (context class) تستخدم الاستراتيجيات:

class ShoppingCart:
    def __init__(self):
        self.total = 0
        self.payment_strategy = None
    
    def add_item(self, price):
        self.total += price
    
    def set_payment_strategy(self, strategy):
        self.payment_strategy = strategy
    
    def checkout(self):
        return self.payment_strategy.pay(self.total)

استخدم نمط الاستراتيجية:

cart = ShoppingCart()
cart.add_item(50)
cart.add_item(30)

# استخدام استراتيجية بطاقة الائتمان
cart.set_payment_strategy(CreditCard())
print(cart.checkout())

# التبديل إلى استراتيجية PayPal
cart.set_payment_strategy(PayPal())
print(cart.checkout())

مثال آخر مع استراتيجيات الفرز:

class BubbleSort:
    def sort(self, data):
        return f"Bubble sorted: {sorted(data)}"

class QuickSort:
    def sort(self, data):
        return f"Quick sorted: {sorted(data)}"

class Sorter:
    def __init__(self, strategy):
        self.strategy = strategy
    
    def set_strategy(self, strategy):
        self.strategy = strategy
    
    def sort_data(self, data):
        return self.strategy.sort(data)

جرّب بنفسك

from abc import ABC, abstractmethod

class PaymentStrategy(ABC):
    @abstractmethod
    def pay(self, amount):
        pass

class CreditCardPayment(PaymentStrategy):
    def __init__(self, card_number, expiry_date, cvv):
        self.card_number = card_number
        self.expiry_date = expiry_date
        self.cvv = cvv
        
    def pay(self, amount):
        print(f"Paying ${amount} using Credit Card: {self.card_number}")
        return True

class PayPalPayment(PaymentStrategy):
    def __init__(self, email, password):
        self.email = email
        self.password = password
        
    def pay(self, amount):
        print(f"Paying ${amount} using PayPal account: {self.email}")
        return True

class ShoppingCart:
    def __init__(self):
        self.items = []
        self.payment_strategy = None
    
    def add_item(self, item, price):
        self.items.append({"item": item, "price": price})
    
    def set_payment_strategy(self, payment_strategy):
        self.payment_strategy = payment_strategy
    
    def checkout(self):
        total = sum(item["price"] for item in self.items)
        if self.payment_strategy:
            return self.payment_strategy.pay(total)
        else:
            raise ValueError("No payment strategy set")

# أنشئ فئة استراتيجية الدفع بالبيتكوين (BitcoinPayment) هنا


if __name__ == "__main__":
    main()
quiz iconاختبر نفسك

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

جميع دروس Object Oriented Programming