Logo

الجزء الثالث: الأنماط السلوكية

2 دقيقتان قراءة
شرائح الدرس
1 / 13

الجزء الثالث: أنماط التصميم السلوكية

Observer وStrategy وCommand

الغرض: تركّز هذه الأنماط على التواصل بين الكائنات وتوزيع المسؤوليات بينها.

3.1 نمط Observer

الفكرة الجوهرية: يعرّف هذا النمط علاقة اعتماد من واحد إلى كثير (One-to-Many)، بحيث عندما يتغيّر حال كائن واحد، تُخطَر كل الكائنات المعتمِدة عليه تلقائيًا. تمامًا مثل نظام الاشتراك في نشرة بريدية.

classDiagram
    class Subject {
        -observers: List~Observer~
        +attach(observer: Observer)
        +detach(observer: Observer)
        +notify()
    }
    
    class Observer {
        <<interface>>
        +update(data)
    }
    
    class ConcreteSubject {
        -state
        +getState()
        +setState(state)
    }
    
    class ConcreteObserverA {
        +update(data)
    }
    
    class ConcreteObserverB {
        +update(data)
    }
    
    Subject <|-- ConcreteSubject
    Observer <|.. ConcreteObserverA
    Observer <|.. ConcreteObserverB
    Subject --> Observer

✅ متى تستخدمه:

  • أنظمة معالجة الأحداث (واجهات المستخدم الرسومية، تفاعلات المستخدم)
  • بنية Model-View المعمارية (مثل MVC وMVP وMVVM)
  • عندما تتطلب التغييرات في كائن واحد تحديث عدة كائنات أخرى
  • تنفيذ معالجة الأحداث الموزّعة
  • التحديثات اللحظية للبيانات (أسعار الأسهم، خلاصات الأخبار)

مثال بالكود:

from abc import ABC, abstractmethod
 
class Observer(ABC):
    @abstractmethod
    def update(self, message):
        pass
 
class Subject:
    def __init__(self):
        self._observers = []
    
    def attach(self, observer):
        self._observers.append(observer)
    
    def detach(self, observer):
        self._observers.remove(observer)
    
    def notify(self, message):
        for observer in self._observers:
            observer.update(message)
 
class WeatherStation(Subject):
    def __init__(self):
        super().__init__()
        self._temperature = 0
    
    @property
    def temperature(self):
        return self._temperature
    
    @temperature.setter
    def temperature(self, temp):
        self._temperature = temp
        self.notify(f"Temperature changed to {temp}°C")
 
class Display(Observer):
    def __init__(self, name):
        self.name = name
    
    def update(self, message):
        print(f"{self.name} received: {message}")
 
# Usage
weather_station = WeatherStation()
phone_display = Display("Phone")
computer_display = Display("Computer")
 
weather_station.attach(phone_display)
weather_station.attach(computer_display)
 
weather_station.temperature = 25  # Both displays get notified
weather_station.temperature = 30  # Both displays get notified again

3.2 نمط Strategy

الفكرة الجوهرية: يعرّف هذا النمط عائلة من الخوارزميات، ويغلّف كل واحدة منها على حدة، ويجعلها قابلة للتبديل فيما بينها. تمامًا مثل اختيار طرق مختلفة للوصول إلى الوجهة نفسها.

classDiagram
    class Context {
        -strategy: Strategy
        +setStrategy(strategy: Strategy)
        +executeStrategy()
    }
    
    class Strategy {
        <<interface>>
        +execute()
    }
    
    class ConcreteStrategyA {
        +execute()
    }
    
    class ConcreteStrategyB {
        +execute()
    }
    
    class ConcreteStrategyC {
        +execute()
    }
    
    Context --> Strategy
    Strategy <|.. ConcreteStrategyA
    Strategy <|.. ConcreteStrategyB
    Strategy <|.. ConcreteStrategyC

✅ متى تستخدمه:

  • وجود عدة طرق لتنفيذ المهمة نفسها
  • تجنّب جمل الشرط الطويلة (Conditional Statements) عند اختيار الخوارزمية
  • تبديل الخوارزمية وقت التشغيل بناءً على الشروط
  • عندما يكون للخوارزميات خصائص أداء مختلفة
  • بنى الإضافات (Plugin Architectures) حيث يمكن تبديل السلوك

مثال بالكود:

from abc import ABC, abstractmethod
 
class PaymentStrategy(ABC):
    @abstractmethod
    def pay(self, amount):
        pass
 
class CreditCardPayment(PaymentStrategy):
    def __init__(self, card_number):
        self.card_number = card_number
    
    def pay(self, amount):
        return f"Paid ${amount} using Credit Card ending in {self.card_number[-4:]}"
 
class PayPalPayment(PaymentStrategy):
    def __init__(self, email):
        self.email = email
    
    def pay(self, amount):
        return f"Paid ${amount} using PayPal account {self.email}"
 
class CryptoPayment(PaymentStrategy):
    def __init__(self, wallet_address):
        self.wallet_address = wallet_address
    
    def pay(self, amount):
        return f"Paid ${amount} using Crypto wallet {self.wallet_address[:8]}..."
 
class ShoppingCart:
    def __init__(self):
        self.items = []
        self.payment_strategy = None
    
    def add_item(self, item, price):
        self.items.append((item, price))
    
    def set_payment_strategy(self, strategy):
        self.payment_strategy = strategy
    
    def checkout(self):
        total = sum(price for item, price in self.items)
        if self.payment_strategy:
            return self.payment_strategy.pay(total)
        return "No payment method selected"
 
# Usage
cart = ShoppingCart()
cart.add_item("Laptop", 1000)
cart.add_item("Mouse", 25)
 
# Try different payment strategies
credit_card = CreditCardPayment("1234567890123456")
paypal = PayPalPayment("[email protected]")
 
cart.set_payment_strategy(credit_card)
print(cart.checkout())  # Paid $1025 using Credit Card ending in 3456
 
cart.set_payment_strategy(paypal)
print(cart.checkout())  # Paid $1025 using PayPal account [email protected]

3.3 نمط Command

الفكرة الجوهرية: يغلّف هذا النمط طلبًا (Request) في صورة كائن مستقل، مما يتيح لك تزويد العملاء بطلبات مختلفة، وترتيب العمليات في طابور تنفيذ، ودعم خاصية التراجع (Undo). تمامًا مثل ريموت كنترول له أزرار مختلفة لكل مهمة.

classDiagram
    class Invoker {
        -command: Command
        +setCommand(command: Command)
        +executeCommand()
    }
    
    class Command {
        <<interface>>
        +execute()
        +undo()
    }
    
    class ConcreteCommand {
        -receiver: Receiver
        -state
        +execute()
        +undo()
    }
    
    class Receiver {
        +action()
    }
    
    class Client {
        +main()
    }
    
    Invoker --> Command
    Command <|.. ConcreteCommand
    ConcreteCommand --> Receiver
    Client --> ConcreteCommand
    Client --> Receiver
    Client --> Invoker

✅ متى تستخدمه:

  • وظائف التراجع/الإعادة (Undo/Redo) في التطبيقات
  • ترتيب العمليات في طابور لتنفيذها لاحقًا
  • تسجيل ومراجعة العمليات (Logging and Auditing)
  • تسجيل وتشغيل الماكرو (Macro Recording and Playback)
  • السلوك المعاملاتي (Transactional Behavior) والتراجع الكامل عن العملية

مثال بالكود:

from abc import ABC, abstractmethod
 
class Command(ABC):
    @abstractmethod
    def execute(self):
        pass
    
    @abstractmethod
    def undo(self):
        pass
 
class Light:
    def __init__(self, location):
        self.location = location
        self.is_on = False
    
    def turn_on(self):
        self.is_on = True
        return f"{self.location} light is ON"
    
    def turn_off(self):
        self.is_on = False
        return f"{self.location} light is OFF"
 
class LightOnCommand(Command):
    def __init__(self, light):
        self.light = light
    
    def execute(self):
        return self.light.turn_on()
    
    def undo(self):
        return self.light.turn_off()
 
class LightOffCommand(Command):
    def __init__(self, light):
        self.light = light
    
    def execute(self):
        return self.light.turn_off()
    
    def undo(self):
        return self.light.turn_on()
 
class RemoteControl:
    def __init__(self):
        self.commands = {}
        self.last_command = None
    
    def set_command(self, slot, command):
        self.commands[slot] = command
    
    def press_button(self, slot):
        if slot in self.commands:
            result = self.commands[slot].execute()
            self.last_command = self.commands[slot]
            return result
        return "No command set for this slot"
    
    def press_undo(self):
        if self.last_command:
            return self.last_command.undo()
        return "No command to undo"
 
# Usage
living_room_light = Light("Living Room")
bedroom_light = Light("Bedroom")
 
living_room_on = LightOnCommand(living_room_light)
living_room_off = LightOffCommand(living_room_light)
bedroom_on = LightOnCommand(bedroom_light)
 
remote = RemoteControl()
remote.set_command(1, living_room_on)
remote.set_command(2, living_room_off)
remote.set_command(3, bedroom_on)
 
print(remote.press_button(1))  # Living Room light is ON
print(remote.press_button(3))  # Bedroom light is ON
print(remote.press_undo())     # Bedroom light is OFF