Logo

الجزء الأول: الأنماط الإنشائية

4 دقائق قراءة
شرائح الدرس
1 / 14

الجزء الأول: أنماط التصميم الإنشائية

Singleton وFactory وBuilder

الغرض: تتعامل هذه الأنماط مع آليات إنشاء الكائنات (Objects)، وتسعى لإنشائها بطريقة تناسب الموقف المطلوب دون تعقيد غير ضروري.

1.1 نمط Singleton

الفكرة الجوهرية: يضمن هذا النمط أن يكون للفئة (Class) نسخة واحدة فقط طوال عمر البرنامج، ويوفّر نقطة وصول عامة إليها من أي مكان في الكود.

classDiagram
    class Singleton {
        -instance: Singleton
        +getInstance(): Singleton
        +operation()
    }
    
    note for Singleton "Only one instance exists"

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

  • مجمّعات اتصال قواعد البيانات (Database Connection Pools) - لأن إنشاء اتصالات متعددة مكلف
  • خدمات تسجيل الأحداث (Logging) - لتجميع السجلات في مكان مركزي واحد
  • مديرو الإعدادات (Configuration Managers) - لضمان مصدر واحد للحقيقة (Single Source of Truth)
  • تطبيقات التخزين المؤقت (Cache) - لمشاركة مساحة الذاكرة نفسها
  • برامج تشغيل الأجهزة (Device Drivers) - للتحكم في الوصول إلى العتاد

مثال بالكود:

class DatabaseConnection:
    _instance = None
    _lock = threading.Lock()
    
    def __new__(cls):
        if cls._instance is None:
            with cls._lock:
                if cls._instance is None:
                    cls._instance = super().__new__(cls)
                    cls._instance.connection = None
        return cls._instance
    
    def connect(self):
        if self.connection is None:
            self.connection = "Connected to Database"
            print("Database connection established")
        return self.connection
 
# Usage
db1 = DatabaseConnection()
db2 = DatabaseConnection()
print(db1 is db2)  # True - Same instance

1.2 نمط Factory

الفكرة الجوهرية: ينشئ هذا النمط الكائنات دون تحديد فئتها (Class) بشكل صريح ومباشر. تمامًا مثل مصنع سيارات يستطيع إنتاج موديلات مختلفة بناءً على المواصفات المطلوبة، دون أن يحتاج العميل لمعرفة تفاصيل خط الإنتاج.

classDiagram
    class AnimalFactory {
        +createAnimal(type: String): Animal
    }
    
    class Animal {
        <<interface>>
        +makeSound()
    }
    
    class Dog {
        +makeSound()
    }
    
    class Cat {
        +makeSound()
    }
    
    AnimalFactory --> Animal
    Dog ..|> Animal
    Cat ..|> Animal

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

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

مثال بالكود:

from abc import ABC, abstractmethod
 
class Animal(ABC):
    @abstractmethod
    def make_sound(self):
        pass
 
class Dog(Animal):
    def make_sound(self):
        return "Woof!"
 
class Cat(Animal):
    def make_sound(self):
        return "Meow!"
 
class AnimalFactory:
    @staticmethod
    def create_animal(animal_type):
        if animal_type.lower() == "dog":
            return Dog()
        elif animal_type.lower() == "cat":
            return Cat()
        else:
            raise ValueError(f"Unknown animal type: {animal_type}")
 
# Usage
factory = AnimalFactory()
dog = factory.create_animal("dog")
cat = factory.create_animal("cat")
print(dog.make_sound())  # Woof!
print(cat.make_sound())  # Meow!
  • مثال من الواقع العملي: يُستخدم نمط Factory كثيرًا في أطر عمل واجهات المستخدم الرسومية (GUI Frameworks)، حيث يمكن إنشاء أنواع مختلفة من الأزرار (مثل WindowsButton و MacButton) بناءً على نظام التشغيل المستخدم.

1.3 نمط Builder

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

classDiagram
    class Pizza {
        +size: String
        +crust: String
        +toppings: List
    }
    
    class PizzaBuilder {
        -pizza: Pizza
        +setSize(size: String): PizzaBuilder
        +setCrust(crust: String): PizzaBuilder
        +addTopping(topping: String): PizzaBuilder
        +build(): Pizza
    }
    
    class Director {
        +makeMargherita(): Pizza
        +makePepperoni(): Pizza
    }
    
    Director --> PizzaBuilder
    PizzaBuilder --> Pizza

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

  • عند إنشاء كائنات لها عدد كبير من المعاملات الاختيارية (أكثر من 4-5 معاملات)
  • عندما يصبح الـ Constructor مثقلًا بعدد كبير جدًا من المعاملات
  • عندما تريد إنشاء تمثيلات مختلفة للكائن نفسه
  • عندما تكون عملية الإنشاء معقّدة وتتم على عدة مراحل
  • عندما تحتاج إلى كائنات غير قابلة للتغيير (Immutable) وتحتوي على حقول كثيرة

مثال بالكود:

class Pizza:
    def __init__(self):
        self.size = None
        self.crust = None
        self.toppings = []
    
    def __str__(self):
        return f"{self.size} {self.crust} pizza with {', '.join(self.toppings)}"
 
class PizzaBuilder:
    def __init__(self):
        self.pizza = Pizza()
    
    def set_size(self, size):
        self.pizza.size = size
        return self
    
    def set_crust(self, crust):
        self.pizza.crust = crust
        return self
    
    def add_topping(self, topping):
        self.pizza.toppings.append(topping)
        return self
    
    def build(self):
        return self.pizza
 
# Usage
pizza = (PizzaBuilder()
         .set_size("Large")
         .set_crust("Thin")
         .add_topping("Pepperoni")
         .add_topping("Mushrooms")
         .build())
 
print(pizza)  # Large Thin pizza with Pepperoni, Mushrooms