chemical-and-materials-engineering
أنماط التصميم في الهندسة البيتونية: قانون الازدحام
Table of Contents
وتمثل أنماط التصميم حلولاً مُختبرة زمنياً لمواجهة التحديات المتكررة في مجال تطوير البرامجيات، وفي هندسة بايتون، تساعد هذه الحلول القابلة لإعادة الاستخدام المطورين على وضع مدونة أكثر قابلية للاستمرار ومرونة وقابلية للتقسيم، ويمكن فهم وتنفيذ أنماط التصميم على نحو فعال أن يغيرا طريقة اقترابكم من هيكل البرامجيات، مما يتيح لكم كتابة رموز لا تعمل فحسب بل أيضاً، بل تكون أكثر انصافاً، ويمكن استخدامها بسهولة في الحفاظ عليها بمرور الوقت.
أنماط التصميم هي بمثابة مُفردات تسمح للمهندسين بالتواصل مع القرارات الهيكلية بشكل مُقتضب عندما يقترح مُطور كبير استخدام نمط معين، فإنهم ينقلون نهجاً معمارياً كاملاً بعدة كلمات، وهذه اللغة المشتركة تُعجل بتعاون الفريق وتكفل للجميع فهم الهيكل الأساسي لقاعدة البيانات.
Understanding Design Patterns in Python Context
(بيثون) لغة برمجة رفيعة المستوى ذات طابع دينامي وملزمة، مما يجعلها لغة دينامية قوية رفيعة المستوى، وهذه المرونة تعطي (بايتون) مزايا فريدة عند تنفيذ أنماط التصميم، ولكن هذا يعني أيضاً أن بعض الأنماط يجب أن تكيف مع إيديولوجيات (بيتون) وقدراته.
كل شيء في بيتون هو موضوع، بما في ذلك المهام، وهي أشياء من الدرجة الأولى، وهذا السمة الأساسية يؤثر على كيفية تنفيذ أنماط التصميم في بايتون مقارنة باللغات الأكثر صلابة ونموذجاً من الناحية الإحصائية، ويتيح الطابع الدينامي للفيتون تنفيذ أنماط كثيرة أكثر إيجازاً، مع إدخال الحاجة أيضاً إلى ممارسات الترميز المُنضبطة.
لأن (بايتون) قوي ومرن جداً نحتاج لبعض القواعد أو الأنماط عندما نبرمجها بدون هذه المبادئ التوجيهية، يمكن أن تصبح قواعد الشفرة غير مرغوبة وصعبة الصيانة، لأن أنماط التصميم توفر الهيكل اللازم لتسخير إمكانات (بيتون) الواسعة مع الحفاظ على جودة الشفرة وقابلية القراءة.
مجموعة الأدوات الثلاثة للتصميم
وتُنظَّم أنماط التصميم تقليدياً إلى ثلاث فئات رئيسية، يتناول كل منها مختلف جوانب تصميم البرامجيات، ويساعد فهم هذه الفئات المطورين على اختيار النمط المناسب لتحدياتهم المحددة.
أنماط الخلق
وتركز الأنماط الخلقية على عملية إنشاء الجسم، وتوفر آليات تزيد من المرونة وإعادة استخدام المدونة القائمة، وتجرد هذه الأنماط عملية التأجيل، وتجعل النظم مستقلة عن كيفية إنشاء الأجسام، وتتكون، وتمثّل.
وبدلا من إنشاء أشياء تستخدم مباشرة جهازا للبناء، توفر أنماط الخلق مزيدا من الرقابة والمرونة على عملية الخلق، وهذا النهج ذو قيمة خاصة عندما يكون منطق الخلق معقدا، عندما تحتاج إلى السيطرة على أي صف يُصبح فوريا، أو عندما تريد إدارة تخصيص الموارد على نحو أكثر كفاءة.
وتشمل أنماط الإبداع المشتركة في بيتسون نظاماً " سينغلتون " وطريقة المصانع و " مصنع " و " بنيدر " و " بروتوك " ، ويخدم كل منهما غرضاً متميزاً في إدارة تعقيدات خلق الأجسام.
أنماط الهياكل الأساسية
وتركز أنماط التصميم الهيكلي على تكوين الفصول أو الأشياء لتشكيل هياكل أكبر وأكثر تعقيدا، والمساعدة في تنظيم وإدارة العلاقات بين الأشياء لتحقيق قدر أكبر من المرونة، وإعادة الاستخدام، والقدرة على الاستمرار، وتهتم هذه الأنماط بكيفية تشكيل الفصول والأجسام بحيث تكون هياكل أكبر، مع الحفاظ على مرونتها وكفاءتها.
فالأنماط الهيكلية تساعد على ضمان عدم ضرورة تعديل الهيكل بأكمله عندما يتغير جزء من النظام، فهي تيسر تصميم نظم يمكن استبدالها أو توسيعها بسهولة دون التأثير على أجزاء أخرى من التطبيق، وتشمل الأنماط الهيكلية المشتركة التكيف والجسر والعقيدة والصانع والواجهة والوزن والثدي.
أنماط السلوك
الأنماط السلوكية تهتم بالخرافيزميات وإحالة المسؤوليات بين الأشياء لا تصف فقط أنماط الأشياء أو الفصول بل أيضا أنماط التواصل بينها
ويخاطب المراقب الاتصالات، مما يتيح للأجزاء المتعددة من النظام أن تستجيب تلقائيا للأحداث أو التغييرات التي تحدثها الدولة، وتشمل أنماط السلوك الأخرى الاستراتيجية والقيادة والتحرير والوسيط وميمتو والدولة وطريقة التمثيل والزوار وسلسلة المسؤولية.
"الخطبة الوحيدة" "مُنحة واحدة للقاعدة"
ويضمن نظام " نغلتون باترن " أن يكون لفئة واحدة فقط في جميع مراحل البرنامج، ويوفر نقطة وصول عالمية، تستخدم عادة لإدارة الموارد المشتركة مثل قواعد البيانات، ونظم قطع الأشجار، أو مديري الملفات، وهذا النمط هو أحد أكثر الأنماط مناقشة وأحياناً ما يثير الجدل في تطوير البرامجيات.
متى تستخدم "سينغلتون"
النمط الأغنيم مفيد بشكل خاص عندما تحتاج إلى درجة واحدة من الدرجة لمراقبة الموارد مثل وصلات قواعد البيانات، أو مديري التشكيلات، أو نظم قطع الأشجار، ويكفل النمط أن جميع الرموز التي تستخدمها هيئة الفصل تعمل مع نفس الغرض، بما يضمن الاتساق عبر التطبيق.
وتشمل حالات الاستخدام المشروع للأوليتون في بيتون ما يلي:
- وصلات بينية تعمل بالموجات الصلبة تمثل موارد مادية فريدة، مثل آلة تصوير واحدة، وطابعة واحدة، أو واجهة واحدة لشبكة GPIO، حيث نماذج واحدة لهذه بدقة
- الطبقة الراقية حيث تريد مخبأ واحد مشترك عبر تطبيقك
- تجمعات الخيوط أو صناديق الاتصالات حيث تريد الحد من الموارد الباهظة الثمن مع أن المجمع نفسه هو واحد على الرغم من الموارد التي يديرها ليست
- نظم إدارة التجمعات التي تحتاج إلى الحفاظ على ظروف متسقة في جميع مراحل التطبيق
- نظم تحديد المواقع التي تعتبر فيها إدارة السجلات المركزية أمراً أساسياً
تنفيذ نظام " سينغلتون " في بايتون
ويمكن تنفيذ فئة العازبين بطرق مختلفة في بايتون، بما في ذلك درجة الأساس، والعاملة في مجال الديكور، ونهج من فئة الميستا، مع أن أفضل طريقة للتنفيذ تناسب هذا الغرض، ولكل طريقة من طرق التنفيذ مزاياها الخاصة ومبادلاتها.
The traditional implementation using the new method looks like this:
class DatabaseConnection:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super(DatabaseConnection, cls).__new__(cls)
cls._instance._initialize()
return cls._instance
def _initialize(self):
self.connection = None
self.host = "localhost"
self.port = 5432
def connect(self):
if not self.connection:
self.connection = f"Connected to {self.host}:{self.port}"
return self.connection
ويستخدم تنفيذ نظام حماية الخيوط جسماً قفلياً يتزامن مع الخيوط أثناء الوصول الأول إلى العنق، وهذا أمر حاسم في التطبيقات المتعددة الطبقات التي يمكن أن تؤدي فيها ظروف العرق إلى حالات متعددة يجري إنشاؤها:
from threading import Lock
class ThreadSafeSingleton:
_instance = None
_lock = Lock()
def __new__(cls):
if cls._instance is None:
with cls._lock:
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
البديل البيثوني: نغمة من المستوى
نظام (بيثون) هو نفسه آلية وحيدة عندما تستورد وحدة، (بيتون) يقوم بتنفيذها مرة ويُخرّج النتيجة في (سايس.مودولز) مع كل استيراد لاحق لقطعة التكويه، وليس جديدة، وهذا يجعل الوحدات طريقة طبيعية وراثية لتنفيذ سلوك واحد.
ولا يستورد بيتسون وحدة إلا مرة واحدة، مما يجعل أي شيء محدد في وحدة نموذجية على نحو فعال، وهو نهج أبسط وأكثر قابلية للاستمرار في كثير من الأحيان من تطبيق فئة رسمية من طراز " سينغلتون " :
# config.py
class _Config:
def __init__(self):
self.database_url = "postgresql://localhost/mydb"
self.api_key = "secret_key"
self.debug_mode = True
def update_setting(self, key, value):
setattr(self, key, value)
# Create the singleton instance
config = _Config()
# In other files, simply import:
# from config import config
نمط العازب عادة لا يبدو منطقياً في (بايتون) في شكله النقي، بدلاً من ذلك، يكون من المنطقي أكثر أن يكون نموذجاً واحداً من الصف و يُسند تلك الحالة إلى متغير عالمي في وحدة نموذجية، هذا النهج أكثر شفافية، أسهل للاختبار، ويُحسّن فلسفة (بيتون).
Unton Drawbacks and Considerations
ويعتبر العديد من المطورين نمط العنق المضاد للدبابات، ولهذا السبب فإن استخدامه في انخفاض قانون بايتون، وهناك عدة شواغل مشروعة:
- نظراً لحالتها العالمية وارتباطها الشديد مع أجزاء أخرى من قاعدة البيانات، يمكن لجهاز (سينغلتون باترن) أن يجعل اختبار الوحدة صعباً، مع السخرية أو استبدال الحالة الوحيدة التي تكون مربكة
- وفي البيئات المتعددة القراء، يمكن أن تستحدث خطة " نغلتون " قضايا تماثل إذا لم تنفذ بعناية، مع وجود خيوط متعددة قد تؤدي إلى حالات متعددة دون التزامن السليم
- العوالق تخلق عوالم مخفية تجعل الشفرة أصعب من فهمها وصيانتها
- فهي تنتهك مبدأ المسؤولية الوحيدة عن طريق إدارة منطقها التجاري وتوقيتها على حد سواء
- Untons make it difficult to extend or modify behavior through inheritance
النظر في استخدام حقن الإعالة بدلاً من ذلك، لأنه يمكن أن يكون أنظف، أو استخدام نموذج على مستوى الوحدات، وكثيراً ما توفر هذه البدائل نفس الفوائد دون عيوب.
أنماط المصانع: اختلاقات مرنة
إن نمط المصانع يوفر واجهة لخلق الأشياء دون تحديد فصولها المحددة، وتشجيع التقارب السائب، وجعل الشفرة أكثر مرونة للتغييرات، وهذا النمط لا يقدر بثمن عندما تحتاج إلى خلق أشياء، ولكن تريد أن تزيل منطق الخلق من الرمز الذي يستخدم تلك الأشياء.
وتركز العوامل على كيفية إنشاء الأجسام، وتخفي المنطق الفوري، وتقليص التقريب الضيق بين المكونات، ومن خلال إضفاء الطابع المركزي على إنشاء الجسم، يجعل نمط المصانع من الأسهل إدخال أنواع جديدة دون تعديل المدونة القائمة.
تنفيذ العوامل البسيطة
نمط المصانع البسيطة يلخص خلق الأجسام في وظيفة أو صف مكرس، هذا مثال عملي لخلق أنواع مختلفة من وصلات قواعد البيانات:
from abc import ABC, abstractmethod
class Database(ABC):
@abstractmethod
def connect(self):
pass
@abstractmethod
def query(self, sql):
pass
class PostgreSQLDatabase(Database):
def connect(self):
return "Connected to PostgreSQL"
def query(self, sql):
return f"PostgreSQL executing: {sql}"
class MySQLDatabase(Database):
def connect(self):
return "Connected to MySQL"
def query(self, sql):
return f"MySQL executing: {sql}"
class MongoDBDatabase(Database):
def connect(self):
return "Connected to MongoDB"
def query(self, sql):
return f"MongoDB executing: {sql}"
class DatabaseFactory:
@staticmethod
def create_database(db_type):
databases = {
'postgresql': PostgreSQLDatabase,
'mysql': MySQLDatabase,
'mongodb': MongoDBDatabase
}
db_class = databases.get(db_type.lower())
if not db_class:
raise ValueError(f"Unknown database type: {db_type}")
return db_class()
# Usage
db = DatabaseFactory.create_database('postgresql')
print(db.connect())
print(db.query("SELECT * FROM users"))
منهجية المصانع
وتوفر طريقة المصانع واجهة لإنشاء أجسام في درجة أعلى ولكنها تتيح للطبقات الفرعية تغيير نوع الأشياء التي ستنشأ، وهذا التباين يعطي مزيدا من المرونة عن طريق تفويض اللحظات إلى الطبقة الفرعية:
from abc import ABC, abstractmethod
class DocumentProcessor(ABC):
@abstractmethod
def create_parser(self):
"""Factory method to be implemented by subclasses"""
pass
def process_document(self, content):
parser = self.create_parser()
return parser.parse(content)
class Parser(ABC):
@abstractmethod
def parse(self, content):
pass
class JSONParser(Parser):
def parse(self, content):
return f"Parsing JSON: {content}"
class XMLParser(Parser):
def parse(self, content):
return f"Parsing XML: {content}"
class CSVParser(Parser):
def parse(self, content):
return f"Parsing CSV: {content}"
class JSONDocumentProcessor(DocumentProcessor):
def create_parser(self):
return JSONParser()
class XMLDocumentProcessor(DocumentProcessor):
def create_parser(self):
return XMLParser()
# Usage
json_processor = JSONDocumentProcessor()
result = json_processor.process_document('{"name": "John"}')
print(result)
استحقاقات خطة المصانع
ويوفر نمط المصانع عدة مزايا قاهرة:
- لا حاجة لمعرفة الفصول الخرسانية التي يتم فرزها على الفور
- Single Responsibility]: يُركز منطق إنشاء الأجسام في مكان واحد
- Open/Closed Principle]: يمكن إضافة أنواع جديدة دون تعديل الرمز القائم
- Flexibility]: easy to shift between different implementations at runtime
- Exability: يمكن بسهولة حقن الأجسام المتحركة لأغراض الاختبار
دورية المراقبين: الهيكل التنظيمي للحدث
يحدد نمط المراقب آلية الاشتراك لإخطار أشياء متعددة عن أي أحداث تحدث للجسم الذي يرصدونه هذا النمط أساسي للبرمجة التي تحركها الأحداث ويستخدم على نطاق واسع في أطر مبادرة غوي، ونظم الوقت الحقيقي، والتطبيقات التفاعلية.
فهم خطة المراقب
وينشئ نمط المراقب تبعية منفردة إلى مانعة بين الأشياء، وعندما يُحدث الموضوع (المستحق) تغييراً، يتم إخطار جميع المعالين (المراقبين) وتحديثهم تلقائياً، وهذا يفصل الموضوع عن مراقبيه، مما يتيح لهم أن يتفاوتوا بصورة مستقلة.
هنا تنفيذ شامل لنمط المراقبه
from abc import ABC, abstractmethod
from typing import List
class Observer(ABC):
@abstractmethod
def update(self, subject):
"""Receive update from subject"""
pass
class Subject(ABC):
def __init__(self):
self._observers: List[Observer] = []
def attach(self, observer: Observer):
"""Attach an observer to the subject"""
if observer not in self._observers:
self._observers.append(observer)
def detach(self, observer: Observer):
"""Detach an observer from the subject"""
try:
self._observers.remove(observer)
except ValueError:
pass
def notify(self):
"""Notify all observers about an event"""
for observer in self._observers:
observer.update(self)
class StockPrice(Subject):
def __init__(self, symbol: str, price: float):
super().__init__()
self._symbol = symbol
self._price = price
@property
def symbol(self):
return self._symbol
@property
def price(self):
return self._price
@price.setter
def price(self, new_price: float):
if new_price != self._price:
self._price = new_price
self.notify()
class StockDisplay(Observer):
def __init__(self, name: str):
self._name = name
def update(self, subject: StockPrice):
print(f"{self._name}: {subject.symbol} is now ${subject.price:.2f}")
class StockAlert(Observer):
def __init__(self, threshold: float):
self._threshold = threshold
def update(self, subject: StockPrice):
if subject.price > self._threshold:
print(f"ALERT: {subject.symbol} exceeded ${self._threshold}! Current: ${subject.price:.2f}")
# Usage
apple_stock = StockPrice("AAPL", 150.00)
display1 = StockDisplay("Display 1")
display2 = StockDisplay("Display 2")
alert = StockAlert(160.00)
apple_stock.attach(display1)
apple_stock.attach(display2)
apple_stock.attach(alert)
apple_stock.price = 155.50
apple_stock.price = 162.00
التطبيقات العالمية الحقيقية
ويستخدم نمط المراقبين على نطاق واسع في تطوير البرامجيات الحديثة:
- ضيف جيد يتعامل مع ]: نقرات بوتون، تحركات الفأر، وأحداث لوحة المفاتيح
- Model-View-Controller (MVC) : Views observe models for data changes
- بيانات الوقت الحقيقي : أسعار المخزونات، تحديثات الطقس، إخطارات وسائط الإعلام الاجتماعية
- Logging Systems]: Multiple log handlers observation application events
- Publish-Subscribe Systems: أسئلة وحوادث
رمز خطة الأداء: توسيع نطاق الأداء الدينامي
نمط الديستور يسمح بإضافة سلوك إلى جسم ما، التأشيرة، التوثيق، إعادة التوثيق، دون تعديل صف الجسم ودون تصنيف فرعي، وهذا النمط يوفر بديلاً مرناً للفصل الفرعي لتوسيع نطاق التشغيل.
Python Decorators vs Decorator Pattern
نمط تصميم (بيثون) و(الرمز) هو نفس السلوك الرابح حول الناظر الحالي دون تعديله، مع (بيتون) يجعل النمط سمة لغوية، وهذا يجعل (بيتون) مصمم بشكل خاص بشكل جيد لتنفيذ وظيفة العزلة.
هنا مثال على استخدام مصممة (بيتون) للديكور
import time
import functools
def timing_decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
print(f"{func.__name__} took {end_time - start_time:.4f} seconds")
return result
return wrapper
def cache_decorator(func):
cache = {}
@functools.wraps(func)
def wrapper(*args):
if args in cache:
print(f"Returning cached result for {args}")
return cache[args]
result = func(*args)
cache[args] = result
return result
return wrapper
def retry_decorator(max_attempts=3):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
for attempt in range(max_attempts):
try:
return func(*args, **kwargs)
except Exception as e:
if attempt == max_attempts - 1:
raise
print(f"Attempt {attempt + 1} failed: {e}. Retrying...")
return None
return wrapper
return decorator
@timing_decorator
@cache_decorator
def fibonacci(n):
if n < 2:
return n
return fibonacci(n-1) + fibonacci(n-2)
@retry_decorator(max_attempts=3)
def unreliable_api_call():
import random
if random.random() < 0.7:
raise ConnectionError("API temporarily unavailable")
return "Success!"
# Usage
print(fibonacci(10))
print(fibonacci(10)) # This will use cached result
آلة فرز خامسة
ويمكن أيضا تنفيذ النمط التقليدي للديكستور باستخدام الفصول، وهو أمر مفيد بالنسبة للسيناريوهات الأكثر تعقيدا:
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.00
def description(self):
return "Simple coffee"
class CoffeeDecorator(Coffee):
def __init__(self, coffee: Coffee):
self._coffee = coffee
def cost(self):
return self._coffee.cost()
def description(self):
return self._coffee.description()
class MilkDecorator(CoffeeDecorator):
def cost(self):
return self._coffee.cost() + 0.50
def description(self):
return self._coffee.description() + ", milk"
class SugarDecorator(CoffeeDecorator):
def cost(self):
return self._coffee.cost() + 0.25
def description(self):
return self._coffee.description() + ", sugar"
class WhippedCreamDecorator(CoffeeDecorator):
def cost(self):
return self._coffee.cost() + 0.75
def description(self):
return self._coffee.description() + ", whipped cream"
# Usage
coffee = SimpleCoffee()
print(f"{coffee.description()}: ${coffee.cost():.2f}")
coffee_with_milk = MilkDecorator(coffee)
print(f"{coffee_with_milk.description()}: ${coffee_with_milk.cost():.2f}")
fancy_coffee = WhippedCreamDecorator(SugarDecorator(MilkDecorator(SimpleCoffee())))
print(f"{fancy_coffee.description()}: ${fancy_coffee.cost():.2f}")
خطة الاستراتيجية: مقاييس قابلة للتبادل
خطة الاستراتيجية تسمح لك بتحديد عائلة من الخوارزميات، وتجميع كل واحد منها، وجعلها قابلة للتبادل في وقت التشغيل، وتفويض السلوك لفصل صفوف أو وظائف الاستراتيجية بدلاً من كتابة كتل كبيرة المشروطة، وهذا النمط ضروري لكتابة مدونة مرنة وقابلة للاستمرار يمكن أن تتكيف مع مختلف المتطلبات.
ويحدد نمط الاستراتيجية أسرة الخوارزميات، ويضع كل منها في صف منفصل، ويجعل أغراضها قابلة للتبادل، مما يتيح اختيار الخوارزميات في وقت غير مناسب على أساس السياق أو التشكيل.
خطة تنفيذ الاستراتيجية
هنا مثال شامل يثبت نمط الإستراتيجية لتجهيز المدفوعات
from abc import ABC, abstractmethod
from typing import Protocol
class PaymentStrategy(Protocol):
def pay(self, amount: float) -> str:
"""Process payment and return confirmation"""
...
class CreditCardPayment:
def __init__(self, card_number: str, cvv: str, expiry: str):
self.card_number = card_number
self.cvv = cvv
self.expiry = expiry
def pay(self, amount: float) -> str:
# Simulate payment processing
masked_card = f"****-****-****-{self.card_number[-4:]}"
return f"Paid ${amount:.2f} using Credit Card {masked_card}"
class PayPalPayment:
def __init__(self, email: str):
self.email = email
def pay(self, amount: float) -> str:
return f"Paid ${amount:.2f} using PayPal account {self.email}"
class CryptocurrencyPayment:
def __init__(self, wallet_address: str, currency: str = "BTC"):
self.wallet_address = wallet_address
self.currency = currency
def pay(self, amount: float) -> str:
return f"Paid ${amount:.2f} using {self.currency} to wallet {self.wallet_address[:10]}..."
class BankTransferPayment:
def __init__(self, account_number: str, routing_number: str):
self.account_number = account_number
self.routing_number = routing_number
def pay(self, amount: float) -> str:
masked_account = f"****{self.account_number[-4:]}"
return f"Paid ${amount:.2f} via bank transfer from account {masked_account}"
class ShoppingCart:
def __init__(self):
self.items = []
self.payment_strategy = None
def add_item(self, item: str, price: float):
self.items.append({'item': item, 'price': price})
def set_payment_strategy(self, strategy: PaymentStrategy):
self.payment_strategy = strategy
def calculate_total(self) -> float:
return sum(item['price'] for item in self.items)
def checkout(self) -> str:
if not self.payment_strategy:
raise ValueError("Payment strategy not set")
total = self.calculate_total()
return self.payment_strategy.pay(total)
# Usage
cart = ShoppingCart()
cart.add_item("Laptop", 999.99)
cart.add_item("Mouse", 29.99)
cart.add_item("Keyboard", 79.99)
# Pay with credit card
cart.set_payment_strategy(CreditCardPayment("1234567890123456", "123", "12/25"))
print(cart.checkout())
# Change strategy to PayPal
cart.set_payment_strategy(PayPalPayment("[email protected]"))
print(cart.checkout())
# Change strategy to Cryptocurrency
cart.set_payment_strategy(CryptocurrencyPayment("1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa"))
print(cart.checkout())
استراتيجية الرئاسية مع الوظائف
وظائف (بيثون) من الدرجة الأولى تسمح بتنفيذ خطة الاستراتيجية بشكل أكثر إيجازاً
def discount_none(total):
return total
def discount_percentage(percentage):
def apply_discount(total):
return total * (1 - percentage / 100)
return apply_discount
def discount_fixed_amount(amount):
def apply_discount(total):
return max(0, total - amount)
return apply_discount
def discount_bulk(threshold, discount_percentage):
def apply_discount(total):
if total >= threshold:
return total * (1 - discount_percentage / 100)
return total
return apply_discount
class Order:
def __init__(self, total: float):
self.total = total
self.discount_strategy = discount_none
def set_discount_strategy(self, strategy):
self.discount_strategy = strategy
def calculate_final_price(self):
return self.discount_strategy(self.total)
# Usage
order = Order(100.00)
print(f"No discount: ${order.calculate_final_price():.2f}")
order.set_discount_strategy(discount_percentage(10))
print(f"10% discount: ${order.calculate_final_price():.2f}")
order.set_discount_strategy(discount_fixed_amount(15))
print(f"$15 off: ${order.calculate_final_price():.2f}")
order.set_discount_strategy(discount_bulk(50, 20))
print(f"Bulk discount: ${order.calculate_final_price():.2f}")
Builder Pattern: Constructing Complex Objects
نمط البناء يسمح لك ببناء أشياء معقدة خطوة، مما يسمح لك بإنتاج أنواع مختلفة من أنواع وتمثيل الجسم باستخدام نفس رمز البناء، وهذا النمط مفيد بشكل خاص عندما يتطلب الجسم خيارات تشكيلية عديدة أو عندما تنطوي عملية البناء على خطوات متعددة.
متى تستخدم الباعة
نمط البناء يشرق في السيناريوهات حيث:
- يتطلب بناء الأجسام الكثير من المعايير الاختيارية
- ويجب أن تتبع عملية التشييد تسلسلا محددا
- عليك أن تخلق تمثيل مختلف للجسم نفسه
- البارامترات المُنشئة ستخلق "مُعدّد التنظيف" مضاد للدبابات
- انشاء الأجسام ينطوي على منطق معقد يجب ان يفصل عن الجسم نفسه
تنفيذ خطة البناء في بايتون
هنا تنفيذ عملي لبناية قواعد البيانات
from typing import List, Optional
from dataclasses import dataclass, field
@dataclass
class Query:
table: str
columns: List[str]
where_clauses: List[str]
joins: List[str]
order_by: Optional[str]
limit: Optional[int]
offset: Optional[int]
def to_sql(self) -> str:
# Select clause
cols = ", ".join(self.columns) if self.columns else "*"
sql = f"SELECT {cols} FROM {self.table}"
# Joins
if self.joins:
sql += " " + " ".join(self.joins)
# Where clause
if self.where_clauses:
sql += " WHERE " + " AND ".join(self.where_clauses)
# Order by
if self.order_by:
sql += f" ORDER BY {self.order_by}"
# Limit and offset
if self.limit:
sql += f" LIMIT {self.limit}"
if self.offset:
sql += f" OFFSET {self.offset}"
return sql
class QueryBuilder:
def __init__(self):
self._table: Optional[str] = None
self._columns: List[str] = []
self._where_clauses: List[str] = []
self._joins: List[str] = []
self._order_by: Optional[str] = None
self._limit: Optional[int] = None
self._offset: Optional[int] = None
def table(self, table_name: str) -> 'QueryBuilder':
self._table = table_name
return self
def select(self, *columns: str) -> 'QueryBuilder':
self._columns.extend(columns)
return self
def where(self, condition: str) -> 'QueryBuilder':
self._where_clauses.append(condition)
return self
def join(self, join_clause: str) -> 'QueryBuilder':
self._joins.append(join_clause)
return self
def order_by(self, column: str, direction: str = "ASC") -> 'QueryBuilder':
self._order_by = f"{column} {direction}"
return self
def limit(self, limit: int) -> 'QueryBuilder':
self._limit = limit
return self
def offset(self, offset: int) -> 'QueryBuilder':
self._offset = offset
return self
def build(self) -> Query:
if not self._table:
raise ValueError("Table name is required")
return Query(
table=self._table,
columns=self._columns,
where_clauses=self._where_clauses,
joins=self._joins,
order_by=self._order_by,
limit=self._limit,
offset=self._offset
)
def reset(self) -> 'QueryBuilder':
self.__init__()
return self
# Usage
builder = QueryBuilder()
# Build a simple query
query1 = (builder
.table("users")
.select("id", "name", "email")
.where("age > 18")
.where("status = 'active'")
.order_by("name", "ASC")
.limit(10)
.build())
print(query1.to_sql())
# Build a complex query with joins
builder.reset()
query2 = (builder
.table("orders")
.select("orders.id", "users.name", "products.title", "orders.total")
.join("INNER JOIN users ON orders.user_id = users.id")
.join("INNER JOIN products ON orders.product_id = products.id")
.where("orders.status = 'completed'")
.where("orders.total > 100")
.order_by("orders.created_at", "DESC")
.limit(20)
.offset(10)
.build())
print(query2.to_sql())
الفوائد المتبادلة الوهمية
وكثيرا ما ينفذ نمط البناء واجهة مؤثرة (تسلسل الميثود)، مما يوفر عدة مزايا:
- Readability: المدونة تقرأ مثل اللغة الطبيعية
- Flexibility]: من السهل إضافة أو إزالة خطوات التشكيل
- Immutability]: يمكن أن يكون الجسم النهائي غير قابل للاشتعال بينما يكون البنّاء قابلاً للطمأن
- Validation]: يمكن لمنطق البناء أن يصادق على الجسم قبل الإنشاء
- Reusability]: يمكن إعادة استخدام البنايات لخلق أجسام متشابهة متعددة
خطة التكيف: جعل أوجه الترابط غير متوافقة تعمل معا
نمط (أدبتر) يسمح للأشياء ذات الوصلات البينية المتضاربة بالتعاون هذا النمط الهيكلي يعمل كجسر بين واجهتين متعارضتين
طريقة التكيف هي نمط تصميم هيكلي يسمح لك بأن تجعل من بينتين متعارضتين تعملان معاً من خلال إقامة جسر بينهما، وهذا أمر ذو قيمة خاصة عندما تدمج المكتبات التابعة لأطراف ثالثة أو مدونة الإرث أو مؤشرات الأداء الخارجية في تطبيقك.
تنفيذ برنامج " ريال - العالم "
النظر في سيناريو حيث تحتاج إلى دمج بوابات الدفع المتعددة مع مختلف الواجهات:
from abc import ABC, abstractmethod
# Target interface that our application expects
class PaymentProcessor(ABC):
@abstractmethod
def process_payment(self, amount: float, currency: str) -> dict:
pass
# Adaptee 1: Stripe API (incompatible interface)
class StripeAPI:
def create_charge(self, amount_cents: int, currency_code: str, source: str):
return {
'id': 'ch_stripe_123',
'amount': amount_cents,
'currency': currency_code,
'status': 'succeeded'
}
# Adaptee 2: PayPal API (different incompatible interface)
class PayPalAPI:
def make_payment(self, total: float, currency_type: str, account: str):
return {
'transaction_id': 'pp_456',
'total_amount': total,
'currency': currency_type,
'state': 'approved'
}
# Adaptee 3: Square API (yet another incompatible interface)
class SquareAPI:
def charge_card(self, money_amount: dict, card_token: str):
return {
'payment_id': 'sq_789',
'amount_money': money_amount,
'status': 'COMPLETED'
}
# Adapter for Stripe
class StripeAdapter(PaymentProcessor):
def __init__(self, stripe_api: StripeAPI):
self.stripe = stripe_api
def process_payment(self, amount: float, currency: str) -> dict:
# Convert dollars to cents for Stripe
amount_cents = int(amount * 100)
# Call Stripe API with adapted parameters
result = self.stripe.create_charge(
amount_cents=amount_cents,
currency_code=currency.upper(),
source='tok_visa'
)
# Adapt the response to our standard format
return {
'success': result['status'] == 'succeeded',
'transaction_id': result['id'],
'amount': amount,
'currency': currency,
'provider': 'Stripe'
}
# Adapter for PayPal
class PayPalAdapter(PaymentProcessor):
def __init__(self, paypal_api: PayPalAPI):
self.paypal = paypal_api
def process_payment(self, amount: float, currency: str) -> dict:
result = self.paypal.make_payment(
total=amount,
currency_type=currency.upper(),
account='[email protected]'
)
return {
'success': result['state'] == 'approved',
'transaction_id': result['transaction_id'],
'amount': amount,
'currency': currency,
'provider': 'PayPal'
}
# Adapter for Square
class SquareAdapter(PaymentProcessor):
def __init__(self, square_api: SquareAPI):
self.square = square_api
def process_payment(self, amount: float, currency: str) -> dict:
money_amount = {
'amount': int(amount * 100),
'currency': currency.upper()
}
result = self.square.charge_card(
money_amount=money_amount,
card_token='cnon:card-token'
)
return {
'success': result['status'] == 'COMPLETED',
'transaction_id': result['payment_id'],
'amount': amount,
'currency': currency,
'provider': 'Square'
}
# Client code that works with the unified interface
class PaymentService:
def __init__(self, processor: PaymentProcessor):
self.processor = processor
def charge_customer(self, amount: float, currency: str = 'USD'):
result = self.processor.process_payment(amount, currency)
if result['success']:
print(f"✓ Payment successful via {result['provider']}")
print(f" Transaction ID: {result['transaction_id']}")
print(f" Amount: {result['amount']} {result['currency']}")
else:
print(f"✗ Payment failed")
return result
# Usage - all payment gateways work through the same interface
stripe_processor = StripeAdapter(StripeAPI())
paypal_processor = PayPalAdapter(PayPalAPI())
square_processor = SquareAdapter(SquareAPI())
# Process payments using different providers
service = PaymentService(stripe_processor)
service.charge_customer(99.99)
service = PaymentService(paypal_processor)
service.charge_customer(149.99)
service = PaymentService(square_processor)
service.charge_customer(199.99)
النموذج: خطة تحديد هيكل ألغوريتوم
ويعرف النموذج هيكل الخوارزمية في الدرجة العليا ولكنه يسمح للطبقات الفرعية بأن تلغي خطوات محددة من الخوارزمية دون تغيير هيكلها، وهذا النمط السلوكي ممتاز في إنفاذ عملية متسقة مع السماح بالتكييف في نقاط محددة.
نموذج التنفيذ
from abc import ABC, abstractmethod
import time
class DataProcessor(ABC):
"""Template class defining the data processing algorithm"""
def process(self, data):
"""Template method defining the algorithm structure"""
print("Starting data processing pipeline...")
# Step 1: Validate
if not self.validate(data):
raise ValueError("Data validation failed")
# Step 2: Extract
extracted = self.extract(data)
# Step 3: Transform
transformed = self.transform(extracted)
# Step 4: Load
result = self.load(transformed)
# Step 5: Cleanup (optional hook)
self.cleanup()
print("Data processing completed successfully")
return result
@abstractmethod
def validate(self, data) -> bool:
"""Validate input data - must be implemented by subclasses"""
pass
@abstractmethod
def extract(self, data):
"""Extract relevant data - must be implemented by subclasses"""
pass
@abstractmethod
def transform(self, data):
"""Transform data - must be implemented by subclasses"""
pass
@abstractmethod
def load(self, data):
"""Load processed data - must be implemented by subclasses"""
pass
def cleanup(self):
"""Optional hook method - can be overridden by subclasses"""
print("Performing default cleanup...")
class CSVDataProcessor(DataProcessor):
def validate(self, data) -> bool:
print("Validating CSV data...")
return isinstance(data, str) and len(data) > 0
def extract(self, data):
print("Extracting CSV data...")
lines = data.strip().split('n')
headers = lines[0].split(',')
rows = [line.split(',') for line in lines[1:]]
return {'headers': headers, 'rows': rows}
def transform(self, data):
print("Transforming CSV data...")
headers = data['headers']
rows = data['rows']
return [dict(zip(headers, row)) for row in rows]
def load(self, data):
print(f"Loading {len(data)} CSV records...")
return data
def cleanup(self):
print("Cleaning up CSV processing resources...")
class JSONDataProcessor(DataProcessor):
def validate(self, data) -> bool:
print("Validating JSON data...")
import json
try:
json.loads(data)
return True
except:
return False
def extract(self, data):
print("Extracting JSON data...")
import json
return json.loads(data)
def transform(self, data):
print("Transforming JSON data...")
if isinstance(data, list):
return [self._flatten_dict(item) for item in data]
return [self._flatten_dict(data)]
def _flatten_dict(self, d, parent_key='', sep='_'):
items = []
for k, v in d.items():
new_key = f"{parent_key}{sep}{k}" if parent_key else k
if isinstance(v, dict):
items.extend(self._flatten_dict(v, new_key, sep=sep).items())
else:
items.append((new_key, v))
return dict(items)
def load(self, data):
print(f"Loading {len(data)} JSON records...")
return data
class XMLDataProcessor(DataProcessor):
def validate(self, data) -> bool:
print("Validating XML data...")
return data.strip().startswith('')
def extract(self, data):
print("Extracting XML data...")
# Simplified XML parsing
return {'xml_content': data}
def transform(self, data):
print("Transforming XML data...")
return {'processed_xml': data['xml_content']}
def load(self, data):
print("Loading XML data...")
return data
def cleanup(self):
print("Cleaning up XML processing resources...")
print("Closing XML parser...")
# Usage
csv_data = """name,age,city
John,30,New York
Jane,25,Los Angeles
Bob,35,Chicago"""
json_data = '''[
{"name": "John", "age": 30, "address": {"city": "New York"}},
{"name": "Jane", "age": 25, "address": {"city": "Los Angeles"}}
]'''
xml_data = "John30"
# Process CSV
csv_processor = CSVDataProcessor()
csv_result = csv_processor.process(csv_data)
print(f"CSV Result: {csv_result}n")
# Process JSON
json_processor = JSONDataProcessor()
json_result = json_processor.process(json_data)
print(f"JSON Result: {json_result}n")
# Process XML
xml_processor = XMLDataProcessor()
xml_result = xml_processor.process(xml_data)
print(f"XML Result: {xml_result}")
متى تستخدم أدوات التصميم
إن معرفة متى تستخدم أنماط التصميم أمر حاسم لتصميم البرامجيات بفعالية، لا سيما عندما تواجه مشاكل تصميم متكررة لها حلول راسخة، لأن أنماط التصميم توفر نُهجاً مُختبرة ومثبتة لمواجهة التحديات المشتركة في تصميم البرامجيات.
حالات الاستخدام الملائمة
استخدام أنماط التصميم لتعزيز قابلية المدونة للتداول والمرونة والاستمرارية، لأنها تساعد في هيكلة المدونة بطريقة تجعل من الأسهل تعديلها وتوسيعها مع تطور المتطلبات.
- تواجه مشكلة تتطابق مع النمط المعروف
- يوفر النمط فوائد واضحة على حل أبسط
- فريقك يفهم النمط ويمكنه الحفاظ عليه
- ويبرر التعقيد الإضافي بتحسين المرونة أو القدرة على الاستمرار
- تريد تحسين التواصل بين أعضاء الفريق
عندما لا تستخدم الباترين
أفضل رمز هو أبسط رمز يحل المشكلة بشكل صحيح في بعض الأحيان هو نمط تصميم جيد في مكانه، ولكن في كثير من الأحيان يكون مجرد وظيفة ومملة.
- الحل الأبسط سيكون جيداً
- أنت تُطبقُ الأنماطَ لمصلحةِ إستعمال الأنماطِ
- النمط يضيف تعقيدات غير ضرورية إلى شفرة مباشرة
- فريقك ليس على دراية بالنمط و الوثائق تفتقر إلى
- المشكلة لا تتطابق مع النمط
كل نمط له مبادلاته الخاصة وعليك أن تهتم أكثر لماذا تختار نمطاً معين من كيفية تنفيذه القرار باستخدام نمط يجب أن يكون مدفوعاً بالمشكلة الموجودة وليس بالرغبة في إظهار المعرفة بالأنماط
Anti-Patterns to Avoid in Python
لا يبدو كل الأنماط منطقية في النظام الإيكولوجي لـ(بيتون) وحدات (بايتون) هي بالفعل وحدة واحدة كل واحدة فقط مرة واحدة
"الخطابات التي لا تُناسب "بايتون
- God Object]: مركزية المنطق أكثر من اللازم في فئة واحدة، تجعل الرمز أصعب في الاختبار والاستمرار، مع وجود بديل أفضل هو تقسيم العمل إلى فصول أصغر حجما ومتماسكة
- Deep Inheritance Hierarchies: Deep inheritance trees make code brittle, so prefer composition and delegation
- "الخلاصات الخفية" "الـ "بيتون" غالباً ما يزيل الحاجة إلى هرميات مُعقدة للوصلات البينية"
النظر في أنماط السلوك الحديثة
في (بيتون) الحديث (3.8+)، يفضل بروتوكول التخمين الهيكلي لأنه لا يتطلب ميراثاً صريحاً مع الفصول التي تفي بالبروتوكول فقط من خلال اتباع الأساليب الصحيحة، بينما تستخدمين (آي بي سي) عندما تريدين إنفاذ الميراث وتوفير تنفيذات غير صحيحة.
استخدام بروتوكولات لطباعة داك
from typing import Protocol
class Drawable(Protocol):
def draw(self) -> str:
...
class Circle:
def draw(self) -> str:
return "Drawing a circle"
class Square:
def draw(self) -> str:
return "Drawing a square"
def render(shape: Drawable) -> None:
print(shape.draw())
# Both Circle and Square satisfy the Drawable protocol
# without explicit inheritance
render(Circle())
render(Square())
أنماط التصميم في تطبيقات بايتون للإنتاج
وفي عام 2026، يجلس بيتسون في تقاطعات AI وتعلم الآلات، وتطوير منتجات قابلة للتكدس، وهندسة بيانات المؤسسة، مع سمتها التي تعكس ميزة هيكلية اكتشفتها الأفرقة الهندسية منذ سنوات: فبيتون يسمح لك بالتحرك بسرعة، والتكامل بسهولة أكبر، وبناء نظم يمكن أن تحافظ عليها الأفرقة، وليس فقط من قبل المؤلف الأصلي.
أنماط الأداء الإطاري - السريع
ويظل ديانغو أكثر إطار بيتون اكتمالاً للأفرقة التي تبنّي منتجات ذات إمكانية الوصول إلى المستعملين المتعددين، ونماذج البيانات المعقدة، والوصلات البينية المخصصة، ونظم التوثيق.
- (ديانجو)
- "السجل الإيجابي" "عارضات (جانغو)
- Template Method]: درجتين
- Middleware Chain]: الطلب/الاستجابة
ويعزز برنامج العمل السريع الملامح والأنماط الحديثة للفيتون:
- Dependency Injection]: Built-in DI system
- Decorator Pattern]: مصممات مقسمات
- Strategy Pattern]: التوثيق القابل للذوبان
- Factory Pattern]: Response model creation
محفوظات
وفي عام 2026، كان توافق الآراء بين أفرقة الهندسة المشهودة في بيتسون أكثر وضوحا: البدء باحتكار محكم الهيكل، وإلغاء الكمال في الخدمات عندما تنشأ حدود محددة من الاستخدام الحقيقي، حيث أن الاحتكار ليس طريقة فشل.
وهربت Instagram على مستعمل واحد من طراز Django في الماضي تماماً قبل 100 مليون مستخدم من إلغاء مهام محددة عالية الحمولة في الخدمات، وكان المفتاح هو بناء الاحتكار مع تفكك الخدمات منذ البداية من خلال حدود واضحة للوحدة، والحد الأدنى من الانقلابات الشاملة لعدة وحدات، وأنماط الاتصال القائمة على الأحداث.
أنماط التصميم الاختبارية
وينبغي أن تجعل أنماط التصميم الرمز أكثر قابلية للاختبار، لا أقل، وهنا استراتيجيات لتنفيذ نمط الاختبار:
خطة استراتيجية الاختبار
import unittest
from unittest.mock import Mock
class TestPaymentStrategies(unittest.TestCase):
def test_credit_card_payment(self):
strategy = CreditCardPayment("1234567890123456", "123", "12/25")
result = strategy.pay(100.00)
self.assertIn("Credit Card", result)
self.assertIn("100.00", result)
def test_paypal_payment(self):
strategy = PayPalPayment("[email protected]")
result = strategy.pay(50.00)
self.assertIn("PayPal", result)
self.assertIn("[email protected]", result)
def test_shopping_cart_with_different_strategies(self):
cart = ShoppingCart()
cart.add_item("Item 1", 50.00)
# Test with credit card
cart.set_payment_strategy(CreditCardPayment("1234", "123", "12/25"))
result1 = cart.checkout()
# Test with PayPal
cart.set_payment_strategy(PayPalPayment("[email protected]"))
result2 = cart.checkout()
self.assertIsNotNone(result1)
self.assertIsNotNone(result2)
مراقب اختبار
class TestObserverPattern(unittest.TestCase):
def test_observer_notification(self):
stock = StockPrice("AAPL", 150.00)
observer = Mock(spec=Observer)
stock.attach(observer)
stock.price = 155.00
observer.update.assert_called_once_with(stock)
def test_multiple_observers(self):
stock = StockPrice("GOOGL", 2800.00)
observer1 = Mock(spec=Observer)
observer2 = Mock(spec=Observer)
stock.attach(observer1)
stock.attach(observer2)
stock.price = 2850.00
observer1.update.assert_called_once()
observer2.update.assert_called_once()
def test_detach_observer(self):
stock = StockPrice("MSFT", 300.00)
observer = Mock(spec=Observer)
stock.attach(observer)
stock.detach(observer)
stock.price = 310.00
observer.update.assert_not_called()
اعتبارات الأداء
وفي حين أن أنماط التصميم تحسن التنظيم الشفروي والقدرة على الاستمرار، فإنها يمكن أن تستحدث نفقات عامة للأداء إذا لم تنفذ بعناية، والنظر في استراتيجيات تحقيق الاستخدام الأمثل لهذه الاستراتيجيات:
الاستيعاب الكسول
ولا تنشأ هذه الحالة إلا عندما يُطلب لأول مرة اتباع أسلوب " الضبط " ، بما يكفل عدم تخصيص الموارد إلا عند الحاجة، وهذا أمر مهم بوجه خاص بالنسبة للأجسام الكثيفة الموارد:
class DatabaseConnection:
_instance = None
_initialized = False
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
def __init__(self):
if not DatabaseConnection._initialized:
self._connect()
DatabaseConnection._initialized = True
def _connect(self):
# Expensive connection operation
print("Establishing database connection...")
self.connection = "Connected"
نتائج الفرز
from functools import lru_cache
@lru_cache(maxsize=128)
def expensive_computation(n):
"""Cached using built-in LRU cache"""
print(f"Computing for {n}...")
return sum(range(n))
# First call computes
result1 = expensive_computation(1000)
# Second call returns cached result
result2 = expensive_computation(1000)
أفضل الممارسات في مجال تصميم أنماط في بيتسون
وينبغي أن تبسط أنماط التصميم، لا أن تعقّد، لأن أنماط تصميم بايتون لا تتعلق بنسخ برمجيات الكتب المدرسية - فهي تتعلق بحل المشاكل الحقيقية بشكل واضح.
1 - التأليف على الميراث
طبيعة (بيثون) الدينامية تجعل التكوين قوياً بشكل خاص بدلاً من التسلسل الهرمي للميراث العميق، تكوّن الأشياء من مكونات أصغر مركزة
# Instead of inheritance
class EmailNotifier:
def send(self, message):
print(f"Sending email: {message}")
class SMSNotifier:
def send(self, message):
print(f"Sending SMS: {message}")
# Use composition
class NotificationService:
def __init__(self):
self.notifiers = []
def add_notifier(self, notifier):
self.notifiers.append(notifier)
def notify(self, message):
for notifier in self.notifiers:
notifier.send(message)
# Usage
service = NotificationService()
service.add_notifier(EmailNotifier())
service.add_notifier(SMSNotifier())
service.notify("Important update!")
2 - استخدام النعناع من النوع للكلار
:: أن تجعل عمليات تنفيذ النمط أكثر وضوحاً، وأن تتيح دعماً أفضل في مجال التنمية المتكاملة:
from typing import Protocol, List
from abc import abstractmethod
class PaymentMethod(Protocol):
def process(self, amount: float) -> bool:
...
class PaymentProcessor:
def __init__(self, methods: List[PaymentMethod]):
self.methods = methods
def charge(self, amount: float) -> bool:
for method in self.methods:
if method.process(amount):
return True
return False
3 - نشرة دورية الوثائق
دائماً توثق أي نمط تستخدمه ولماذا
class DataExporter:
"""
Uses the Strategy pattern to support multiple export formats.
This allows adding new export formats without modifying existing code,
following the Open/Closed Principle.
Example:
exporter = DataExporter(JSONExportStrategy())
exporter.export(data)
"""
def __init__(self, strategy: ExportStrategy):
self._strategy = strategy
def export(self, data):
return self._strategy.export(data)
4 - إبقاءه بسيطا
لا تبالغ في الهندسة، ابدأوا ببساطة وثبات للأنماط عندما يكون التعقيد مبرراً لذلك
# Simple is often better
def calculate_discount(price, customer_type):
discounts = {
'regular': 0,
'premium': 0.10,
'vip': 0.20
}
return price * (1 - discounts.get(customer_type, 0))
# Only introduce Strategy pattern when you need:
# - Runtime strategy switching
# - Complex discount logic
# - Multiple discount calculation methods
الموارد المخصصة لأوامر تصميم التعلم
لتعميق فهمك لأنماط التصميم في (بيتون) ، إستكشف هذه الموارد القيمة
- Refactoring.Guru]: Global design pattern catalog with Python examples at ]https://refactoring.guru/design-patterns/python
- Python Patterns Guide ]: Brandon Rhodes' evolving guide at ]https://python-patterns.guide/
- GitHub Python Patterns]: Community-driven pattern collection at ]https://github.com/faif/python-patterns
- Real Python]: Practical tutorials on Python design patterns at ]https://realpython.com]
- GeeksforGeeks Python Design Patterns]: تعميم في ]https://www.geeksforgeeks.org/python-design-patterns/]
خاتمة
أنماط التصميم أدوات قوية في مجموعة أدوات مهندسي (بيتون) ولكن يجب تطبيقها بحزم، الإستراتيجية، المصانع، والأنماط المراقبة غالبا ما تظهر معا في نظم (بيتون) ذات نظام جيد البحث، مع تركيز الاستراتيجية على اختيار ومسح الخوارزميات، التركيز على كيفية إنشاء الأشياء، والمراقب عن معالجة الاتصالات، مع فهم هذه التميزات تساعدك على اختيار النمط الصحيح
مفتاح النجاح في استخدام أنماط التصميم في (بيثون) هو فهم كل من الأنماط نفسها وخصائص (بايتون) الفريدة، وضع البطاقات الدينامية، وظائف الدرجة الأولى، والمكتبة الموحّدة القوية غالباً ما تسمح بتنفيذات أبسط من اللغات التي يُطبع بها النظام الإحصائي، وتعطي الأولوية للوضوح الرمزي وقابلية الحفظ على النمط.
تذكروا أن الأنماط هي وسيلة لتحقيق غاية، وليس غاية في حد ذاتها، الهدف هو كتابة رمز سهل الفهم والاختبار والتعديل، عندما يساعد نمط على تحقيق ذلك الهدف، استخدموه، عندما يكون الحل أبسط، يفي بالبساطة، مع اكتسابكم الخبرة، ستطورون حدساً عندما تضيف الأنماط قيمة، وعندما تضيفون تعقيدات غير ضرورية.
بتقنية أنماط التصميم وفهم متى تطبقها ستكون أفضل تجهيزاً لبناء تطبيقات قوية و قابلة للتوسع في البيتون التي تصمد أمام اختبار الزمن وتطور المتطلبات