9.2.1 الگو Decorator

9.2.1 الگو Decorator

9.2.4.1 - توضیح الگوی Decorator #

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

9.2.4.2 - مثال عملی #

package main

import "fmt"

// Component Interface
type Coffee interface {
    Cost() float64
    Description() string
}

// Concrete Component - Basic Coffee
type BasicCoffee struct{}

func (b *BasicCoffee) Cost() float64 {
    return 2.00
}

func (b *BasicCoffee) Description() string {
    return "Basic Coffee"
}

// Decorator Base
type CoffeeDecorator struct {
    coffee Coffee
}

func (c *CoffeeDecorator) Cost() float64 {
    return c.coffee.Cost()
}

func (c *CoffeeDecorator) Description() string {
    return c.coffee.Description()
}

// Concrete Decorator - Milk
type MilkDecorator struct {
    CoffeeDecorator
}

func NewMilkDecorator(coffee Coffee) *MilkDecorator {
    return &MilkDecorator{CoffeeDecorator{coffee: coffee}}
}

func (m *MilkDecorator) Cost() float64 {
    return m.coffee.Cost() + 0.50
}

func (m *MilkDecorator) Description() string {
    return m.coffee.Description() + ", Milk"
}

// Concrete Decorator - Sugar
type SugarDecorator struct {
    CoffeeDecorator
}

func NewSugarDecorator(coffee Coffee) *SugarDecorator {
    return &SugarDecorator{CoffeeDecorator{coffee: coffee}}
}

func (s *SugarDecorator) Cost() float64 {
    return s.coffee.Cost() + 0.25
}

func (s *SugarDecorator) Description() string {
    return s.coffee.Description() + ", Sugar"
}

// Concrete Decorator - Caramel Syrup
type CaramelDecorator struct {
    CoffeeDecorator
}

func NewCaramelDecorator(coffee Coffee) *CaramelDecorator {
    return &CaramelDecorator{CoffeeDecorator{coffee: coffee}}
}

func (c *CaramelDecorator) Cost() float64 {
    return c.coffee.Cost() + 1.00
}

func (c *CaramelDecorator) Description() string {
    return c.coffee.Description() + ", Caramel Syrup"
}

func main() {
    // Start with basic coffee
    coffee := &BasicCoffee{}
    fmt.Printf("%s: $%.2f\n", coffee.Description(), coffee.Cost())
    
    // Add milk
    coffeeWithMilk := NewMilkDecorator(coffee)
    fmt.Printf("%s: $%.2f\n", coffeeWithMilk.Description(), coffeeWithMilk.Cost())
    
    // Add sugar to coffee with milk
    coffeeWithMilkAndSugar := NewSugarDecorator(coffeeWithMilk)
    fmt.Printf("%s: $%.2f\n", coffeeWithMilkAndSugar.Description(), coffeeWithMilkAndSugar.Cost())
    
    // Add caramel to everything
    fancyCoffee := NewCaramelDecorator(coffeeWithMilkAndSugar)
    fmt.Printf("%s: $%.2f\n", fancyCoffee.Description(), fancyCoffee.Cost())
    
    // Let's create some different combinations
    fmt.Println("\nDifferent coffee orders:")
    
    // Just caramel coffee
    caramelCoffee := NewCaramelDecorator(&BasicCoffee{})
    fmt.Printf("%s: $%.2f\n", caramelCoffee.Description(), caramelCoffee.Cost())
    
    // Coffee with sugar only
    sweetCoffee := NewSugarDecorator(&BasicCoffee{})
    fmt.Printf("%s: $%.2f\n", sweetCoffee.Description(), sweetCoffee.Cost())
    
    // Premium coffee with everything
    premiumCoffee := NewCaramelDecorator(
        NewMilkDecorator(
            NewSugarDecorator(
                &BasicCoffee{},
            ),
        ),
    )
    fmt.Printf("%s: $%.2f\n", premiumCoffee.Description(), premiumCoffee.Cost())
}

در این پیاده‌سازی الگوی Decorator، رابط Coffee به عنوان کامپوننت پایه تعریف شده که متدهای Cost و Description را شامل می‌شود. کلاس BasicCoffee به عنوان Concrete Component، پیاده‌سازی ساده‌ای از این رابط ارائه می‌دهد. ساختار CoffeeDecorator به عنوان پایه برای تمام دکوراتورها عمل کرده و یک نمونه از Coffee را در خود نگهداری می‌کند. سه دکوراتور بتن MilkDecorator، SugarDecorator و CaramelDecorator از CoffeeDecorator embed کرده و هر کدام با اضافه کردن هزینه و توضیحات جدید، عملکرد قهوه پایه را گسترش می‌دهند. در تابع main، با ایجاد ترکیبات مختلفی از دکوراتورها روی قهوه پایه نشان داده شده که چگونه می‌توان به صورت پویا و مرحله‌ای قابلیت‌های جدیدی به شیء اضافه کرد، به طوری که از قهوه ساده شروع شده و به تدریج با اضافه کردن شیر، شکر و کارامل به یک قهوه مجلل تبدیل می‌شود، بدون اینکه ساختار اصلی کلاس BasicCoffee تغییر کند.