Logo

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

3 دقائق قراءة
شرائح الدرس
1 / 13

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

Adapter وDecorator وFacade

الغرض: تتعامل هذه الأنماط مع تكوين الكائنات (Object Composition) والعلاقات بين الكيانات المختلفة.

2.1 نمط Adapter

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

classDiagram
    class Target {
        <<interface>>
        +request()
    }
    
    class Adapter {
        -adaptee: Adaptee
        +request()
    }
    
    class Adaptee {
        +specificRequest()
    }
    
    class Client {
        +main()
    }
    
    Client --> Target
    Adapter ..|> Target
    Adapter --> Adaptee

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

  • عند دمج مكتبات خارجية (Third-Party Libraries) لها واجهات مختلفة عن واجهتك
  • عند دمج كود قديم (Legacy Code) دون الحاجة لتعديله
  • لجعل فئات غير متوافقة تعمل معًا
  • عندما لا تستطيع تعديل الفئات الموجودة أصلًا
  • لإنشاء فئات قابلة لإعادة الاستخدام تعمل مع فئات غير مرتبطة بها

مثال بالكود:

# Old system
class OldPrinter:
    def old_print(self, text):
        return f"Old printer: {text}"
 
# New interface expected by client
class ModernPrinter:
    def print(self, text):
        return f"Modern printer: {text}"
 
# Adapter to make old printer work with new interface
class PrinterAdapter:
    def __init__(self, old_printer):
        self.old_printer = old_printer
    
    def print(self, text):
        return self.old_printer.old_print(text)
 
# Client code
def client_code(printer):
    return printer.print("Hello World")
 
# Usage
old_printer = OldPrinter()
adapter = PrinterAdapter(old_printer)
modern_printer = ModernPrinter()
 
print(client_code(adapter))        # Old printer: Hello World
print(client_code(modern_printer)) # Modern printer: Hello World

2.2 نمط Decorator

الفكرة الجوهرية: يضيف هذا النمط وظائف جديدة إلى الكائنات بشكل ديناميكي دون تغيير بنيتها الأساسية. تمامًا مثل إضافة إكسسوارات لغطاء الهاتف.

classDiagram
    class Component {
        <<interface>>
        +operation()
    }
    
    class ConcreteComponent {
        +operation()
    }
    
    class Decorator {
        <<abstract>>
        -component: Component
        +operation()
    }
    
    class ConcreteDecoratorA {
        +operation()
        +addedBehavior()
    }
    
    class ConcreteDecoratorB {
        +operation()
        +addedState
    }
    
    Component <|.. ConcreteComponent
    Component <|.. Decorator
    Decorator <|-- ConcreteDecoratorA
    Decorator <|-- ConcreteDecoratorB
    Decorator --> Component

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

  • عند إضافة مسؤوليات جديدة للكائنات ديناميكيًا وقت التشغيل
  • عندما يؤدي استخدام الوراثة الفرعية (Subclassing) إلى انفجار في عدد الفئات
  • لتوسيع الوظائف دون تعديل الكود الموجود
  • عندما تحتاج إلى تركيبات مختلفة من السلوكيات
  • لإنشاء سلوك قابل للتهيئة (Configurable) للكائنات

مثال بالكود:

from abc import ABC, abstractmethod
 
class Coffee(ABC):
    @abstractmethod
    def cost(self):
        pass
    
    @abstractmethod
    def description(self):
        pass
 
class SimpleCoffee(Coffee):
    def cost(self):
        return 2.0
    
    def description(self):
        return "Simple coffee"
 
class CoffeeDecorator(Coffee):
    def __init__(self, coffee):
        self._coffee = coffee
    
    def cost(self):
        return self._coffee.cost()
    
    def description(self):
        return self._coffee.description()
 
class Milk(CoffeeDecorator):
    def cost(self):
        return self._coffee.cost() + 0.5
    
    def description(self):
        return self._coffee.description() + ", milk"
 
class Sugar(CoffeeDecorator):
    def cost(self):
        return self._coffee.cost() + 0.2
    
    def description(self):
        return self._coffee.description() + ", sugar"
 
# Usage
coffee = SimpleCoffee()
coffee_with_milk = Milk(coffee)
coffee_with_milk_and_sugar = Sugar(coffee_with_milk)
 
print(f"{coffee_with_milk_and_sugar.description()}: ${coffee_with_milk_and_sugar.cost()}")
# Output: Simple coffee, milk, sugar: $2.7

2.3 نمط Facade

الفكرة الجوهرية: يوفّر هذا النمط واجهة مبسّطة لنظام فرعي (Subsystem) معقّد. تمامًا مثل ريموت كنترول التلفاز الذي يخفي عنك تعقيد الأنظمة الداخلية للتلفاز.

classDiagram
    class Facade {
        -subsystem1: SubsystemA
        -subsystem2: SubsystemB  
        -subsystem3: SubsystemC
        +operation()
    }
    
    class SubsystemA {
        +operationA1()
        +operationA2()
    }
    
    class SubsystemB {
        +operationB1()
        +operationB2()
    }
    
    class SubsystemC {
        +operationC1()
        +operationC2()
    }
    
    class Client {
        +main()
    }
    
    Client --> Facade
    Facade --> SubsystemA
    Facade --> SubsystemB
    Facade --> SubsystemC

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

  • لتبسيط واجهات برمجة التطبيقات (APIs) أو الأنظمة الفرعية المعقّدة
  • لتوفير واجهة موحّدة لمجموعة من الواجهات
  • لفصل العملاء (Clients) عن الأنظمة الفرعية المعقّدة
  • لإنشاء طبقات من التجريد (Abstraction)
  • عندما تريد إخفاء تفاصيل التنفيذ الداخلية

مثال بالكود:

# Complex subsystems
class DVDPlayer:
    def on(self):
        return "DVD Player is on"
    
    def play(self, movie):
        return f"Playing '{movie}'"
    
    def off(self):
        return "DVD Player is off"
 
class SoundSystem:
    def on(self):
        return "Sound System is on"
    
    def set_volume(self, level):
        return f"Volume set to {level}"
    
    def off(self):
        return "Sound System is off"
 
class Projector:
    def on(self):
        return "Projector is on"
    
    def wide_screen_mode(self):
        return "Projector in widescreen mode"
    
    def off(self):
        return "Projector is off"
 
# Facade
class HomeTheaterFacade:
    def __init__(self):
        self.dvd = DVDPlayer()
        self.sound = SoundSystem()
        self.projector = Projector()
    
    def watch_movie(self, movie):
        actions = [
            self.projector.on(),
            self.projector.wide_screen_mode(),
            self.sound.on(),
            self.sound.set_volume(5),
            self.dvd.on(),
            self.dvd.play(movie)
        ]
        return actions
    
    def end_movie(self):
        actions = [
            self.dvd.off(),
            self.sound.off(),
            self.projector.off()
        ]
        return actions
 
# Usage
theater = HomeTheaterFacade()
print("Starting movie:")
for action in theater.watch_movie("The Matrix"):
    print(f"  - {action}")