1. چیست الگوی دیکوراتور

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

2. ویژگی‌ها و مزایای الگوی دیکوراتور

ویژگی‌ها و مزایای الگوی دیکوراتور شامل:

  • گسترش پویا وظیفه یک شیء بدون تغییر کد آن.
  • تطابق با اصل باز-بسته بودن، امکان افزودن و حذف داینامیک دیکوراتورها.
  • قابلیت ترکیب چند دیکوراتور برای دستیابی به گسترش‌های توابع تودرتو.
  • استقلال دیکوراتورها از روش دکوره شدن شیء، که اجازه می‌دهد تغییرات به صورت مستقل صورت گیرد.

3. نمونه‌های کاربردی از الگوی دیکوراتور

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

  • افزودن وظایف لاگ گیری به صورت دینامیک
  • افزودن وظایف کش نمودن به صورت دینامیک
  • اعتبار سنجی داده‌های دینامیک

4. پیاده‌سازی الگوی دیکوراتور در Golang

4.1. نمودار کلاس UML

الگوی دیکوراتور در Golang

4.2. معرفی مثال

در این مثال، یک رابط Component و یک کلاس ConcreteComponent که عملیات متد رابط Component را پیاده‌سازی می‌کند وجود دارد.

سپس یک کلاس Decorator وجود دارد که همچنین رابط Component را پیاده‌سازی می‌کند. کلاس Decorator دارای یک متغیر عضو از نوع Component است.

هر دو کلاس ConcreteDecoratorA و ConcreteDecoratorB از کلاس Decorator ارث بری کرده و با نوشتن مجدد متد Operation، وظایف اضافی را پیاده‌سازی می‌کنند.

4.3. گام پیاده‌سازی 1: تعریف رابط و کلاس پیاده‌سازی

type Component interface {
	Operation() string
}

type ConcreteComponent struct {}

func (c *ConcreteComponent) Operation() string {
	return "specific component operation"
}

4.4. گام پیاده‌سازی 2: تعریف دیکوره

type Decorator struct {
	component Component
}

func (d *Decorator) Operation() string {
	return d.component.Operation()
}

4.5. گام پیاده‌سازی 3: پیاده‌سازی دیکوره

type ConcreteDecoratorA struct {
	Decorator
	addedState string
}

func (c *ConcreteDecoratorA) Operation() string {
	c.addedState = "New State"
	return c.addedState + " " + c.component.Operation()
}

type ConcreteDecoratorB struct {
	Decorator
}

func (c *ConcreteDecoratorB) Operation() string {
	return "specific decorator B operation " + c.component.Operation()
}

4.6. گام پیاده‌سازی 4: استفاده از دیکوره

func main() {
	component := &ConcreteComponent{}

	decoratorA := &ConcreteDecoratorA{}
	decoratorA.component = component

	decoratorB := &ConcreteDecoratorB{}
	decoratorB.component = decoratorA

	result := decoratorB.Operation()
	fmt.Println(result)
}

5. مقایسه الگوی دیکوراتور با الگوی طراحی دیگر

5.1. مقایسه با ارث بری

در مقایسه با ارث بری، الگوی دیکوراتور می‌تواند به صورت پویا وظیفه را اضافه کند بدون تغییر کد موجود، در حالی که ارث بری استاتیک است و نیاز به تعیین در زمان کامپایل دارد.

5.2. مقایسه با الگوی استاتیک پراکسی

الگوی دیکوراتور و الگوی پراکسی استاتیک هر دو می‌توانند گسترش وظایف را دست یابند، اما الگوی دیکوراتور انعطاف‌پذیرتر است و امکان افزودن و حذف داینامیک وظایف را فراهم می‌کند.

5.3. مقایسه با الگوی داینامیک پراکسی

هر دو الگوی دیکوراتور و الگوی پراکسی داینامیک می‌توانند وظایف اشیاء را در زمان اجرا گسترش دهند. با این حال، الگوی دیکوراتور یک شیء را دیکوره می‌کند، در حالی که الگوی پراکسی داینامیک دارای دسترسی غیرمستقیم بین شیء پراکسی و شیء هدف است.