الگوی طراحی زنجیره تزئین‌گر (Decorator Chain) در پایتون

الگوی طراحی زنجیره تزئین‌گر (Decorator Chain) در پایتون

در دنیای برنامه‌نویسی، ما اغلب با نیاز به افزودن رفتار یا مسئولیت‌های جدید به اشیاء موجود بدون تغییر در ساختار آن‌ها مواجه می‌شویم. اینجاست که الگوهای طراحی به کمک ما می‌آیند. یکی از این الگوها، الگوی زنجیره تزئین‌گر (Decorator Chain) است که به ما امکان می‌دهد به صورت پویا و انعطاف‌پذیر، مسئولیت‌های جدید را به اشیاء اضافه کنیم.

مقدمه و مفهوم کلی

الگوی زنجیره تزئین‌گر یک الگوی طراحی ساختاری است که به شما اجازه می‌دهد تا به صورت پویا مسئولیت‌های جدیدی را به یک شیء اضافه کنید. این الگو از ترکیب اشیاء استفاده می‌کند تا رفتار جدیدی را ارائه دهد. برخلاف وراثت، که رفتار را به صورت استاتیک در زمان کامپایل تعیین می‌کند، تزئین‌گر به شما امکان می‌دهد تا رفتار را در زمان اجرا تغییر دهید. این انعطاف‌پذیری، الگوی تزئین‌گر را برای مواردی که نیاز به افزودن رفتار به صورت پویا دارید، بسیار مناسب می‌کند.

تصور کنید یک فنجان قهوه دارید. شما می‌توانید به آن شکر، شیر، خامه یا طعم‌دهنده‌های دیگر اضافه کنید. هر کدام از این افزودنی‌ها، یک تزئین‌گر هستند که رفتار فنجان قهوه را تغییر می‌دهند. فنجان قهوه اصلی، شیء اصلی است و افزودنی‌ها، تزئین‌گرها هستند که به صورت زنجیره‌ای به آن اضافه می‌شوند.

اجزای اصلی الگوی تزئین‌گر

الگوی تزئین‌گر از سه جزء اصلی تشکیل شده است:

  • Component (رابط): این رابط، نوعی رفتار یا ویژگی را تعریف می‌کند که اشیاء می‌توانند آن را داشته باشند.
  • Concrete Component (اجزای واقعی): این کلاس، پیاده‌سازی اصلی رابط Component است.
  • Decorator (تزئین‌گر): این کلاس، یک Component را نگه می‌دارد و رفتار جدیدی را به آن اضافه می‌کند. تزئین‌گرها نیز باید رابط Component را پیاده‌سازی کنند تا بتوانند به عنوان Component عمل کنند.
  • Concrete Decorator (تزئین‌گرهای واقعی): این کلاس‌ها، تزئین‌گرها را پیاده‌سازی می‌کنند و مسئولیت‌های خاصی را به Component اضافه می‌کنند.

پیاده‌سازی الگوی تزئین‌گر در پایتون

بیایید یک مثال عملی از پیاده‌سازی الگوی تزئین‌گر در پایتون را بررسی کنیم. فرض کنید یک کلاس Coffee داریم که نشان‌دهنده یک فنجان قهوه است. ما می‌خواهیم بتوانیم به این فنجان قهوه، شکر، شیر و خامه اضافه کنیم.

class Coffee:
    def __init__(self):
        self.description = "قهوه ساده"

    def get_description(self):
        return self.description

    def get_cost(self):
        return 5

class CoffeeDecorator:
    def __init__(self, coffee):
        self.coffee = coffee

    def get_description(self):
        return self.coffee.get_description()

    def get_cost(self):
        return self.coffee.get_cost()

class SugarDecorator(CoffeeDecorator):
    def __init__(self, coffee):
        super().__init__(coffee)
        self.description = "شکر اضافه شده"

    def get_description(self):
        return self.coffee.get_description() + ", " + self.description

    def get_cost(self):
        return self.coffee.get_cost() + 2

class MilkDecorator(CoffeeDecorator):
    def __init__(self, coffee):
        super().__init__(coffee)
        self.description = "شیر اضافه شده"

    def get_description(self):
        return self.coffee.get_description() + ", " + self.description

    def get_cost(self):
        return self.coffee.get_cost() + 3

class CreamDecorator(CoffeeDecorator):
    def __init__(self, coffee):
        super().__init__(coffee)
        self.description = "خامه اضافه شده"

    def get_description(self):
        return self.coffee.get_description() + ", " + self.description

    def get_cost(self):
        return self.coffee.get_cost() + 4

# مثال استفاده
coffee = Coffee()
print(coffee.get_description() + ": " + str(coffee.get_cost()))

coffee_with_sugar = SugarDecorator(coffee)
print(coffee_with_sugar.get_description() + ": " + str(coffee_with_sugar.get_cost()))

coffee_with_milk = MilkDecorator(coffee_with_sugar)
print(coffee_with_milk.get_description() + ": " + str(coffee_with_milk.get_cost()))

coffee_with_cream = CreamDecorator(coffee_with_milk)
print(coffee_with_cream.get_description() + ": " + str(coffee_with_cream.get_cost()))

در این مثال، Coffee کلاس اصلی است و SugarDecorator، MilkDecorator و CreamDecorator تزئین‌گرها هستند. هر تزئین‌گر، یک شیء Coffee را نگه می‌دارد و رفتار جدیدی را به آن اضافه می‌کند. با استفاده از این تزئین‌گرها، می‌توانیم به صورت پویا و انعطاف‌پذیر، فنجان قهوه را با افزودنی‌های مختلف تزئین کنیم.

مزایای استفاده از الگوی تزئین‌گر

الگوی تزئین‌گر مزایای متعددی دارد:

  • انعطاف‌پذیری: این الگو به شما امکان می‌دهد تا رفتار اشیاء را در زمان اجرا تغییر دهید.
  • قابلیت گسترش: شما می‌توانید به راحتی تزئین‌گرهای جدیدی را بدون تغییر در کلاس‌های موجود اضافه کنید.
  • جلوگیری از تورم کلاس: با استفاده از تزئین‌گرها، می‌توانید از ایجاد کلاس‌های متعدد با ترکیب‌های مختلف رفتار جلوگیری کنید.
  • رعایت اصل مسئولیت واحد: هر تزئین‌گر مسئولیت خاصی را بر عهده دارد و این امر باعث می‌شود که کلاس‌ها ساده‌تر و قابل نگهداری‌تر باشند.

معایب استفاده از الگوی تزئین‌گر

الگوی تزئین‌گر نیز معایبی دارد:

  • افزایش تعداد کلاس‌ها: با افزودن تزئین‌گرهای بیشتر، تعداد کلاس‌ها افزایش می‌یابد که می‌تواند پیچیدگی کد را افزایش دهد.
  • مشکل در دیباگ: زنجیره‌ای از تزئین‌گرها می‌تواند دیباگ کد را دشوارتر کند.
  • پیچیدگی در مدیریت: مدیریت تعداد زیادی تزئین‌گر می‌تواند پیچیده باشد.

موارد استفاده از الگوی تزئین‌گر

الگوی تزئین‌گر در موارد مختلفی کاربرد دارد، از جمله:

  • افزودن قابلیت لاگ‌برداری به یک برنامه: می‌توانید از تزئین‌گرها برای افزودن قابلیت لاگ‌برداری به توابع مختلف استفاده کنید.
  • افزودن قابلیت اعتبارسنجی به یک فرم: می‌توانید از تزئین‌گرها برای افزودن قابلیت اعتبارسنجی به فیلدهای مختلف یک فرم استفاده کنید.
  • افزودن قابلیت کش‌کردن به یک تابع: می‌توانید از تزئین‌گرها برای افزودن قابلیت کش‌کردن به توابع پرهزینه استفاده کنید.
  • پیاده‌سازی سیستم‌های مجوز: می‌توانید از تزئین‌گرها برای پیاده‌سازی سیستم‌های مجوز و کنترل دسترسی استفاده کنید.

تفاوت بین تزئین‌گر و وراثت

تزئین‌گر و وراثت هر دو روش‌هایی برای افزودن رفتار به اشیاء هستند، اما تفاوت‌های مهمی بین آن‌ها وجود دارد. وراثت، رفتار را به صورت استاتیک در زمان کامپایل تعیین می‌کند، در حالی که تزئین‌گر، رفتار را به صورت پویا در زمان اجرا تغییر می‌دهد. وراثت، یک رابطه “is-a” ایجاد می‌کند (به عنوان مثال، یک Dog یک Animal است)، در حالی که تزئین‌گر، یک رابطه “has-a” ایجاد می‌کند (به عنوان مثال، یک Coffee دارای Sugar است). تزئین‌گر انعطاف‌پذیری بیشتری نسبت به وراثت دارد، زیرا به شما امکان می‌دهد تا رفتار را در زمان اجرا تغییر دهید و از ایجاد کلاس‌های متعدد با ترکیب‌های مختلف رفتار جلوگیری کنید.

نتیجه‌گیری

الگوی زنجیره تزئین‌گر یک الگوی طراحی قدرتمند و انعطاف‌پذیر است که به شما امکان می‌دهد تا به صورت پویا و بدون تغییر در ساختار اشیاء موجود، مسئولیت‌های جدید را به آن‌ها اضافه کنید. این الگو در موارد مختلفی کاربرد دارد و می‌تواند به شما در نوشتن کدهای تمیزتر، قابل نگهداری‌تر و قابل گسترش‌تر کمک کند. با درک مفاهیم و مزایای این الگو، می‌توانید از آن در پروژه‌های خود استفاده کنید و کیفیت کد خود را بهبود بخشید.

بدون دیدگاه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *