文章

设计模式解密:装饰器模式的终极指南(PHP/Go双实现)

一、什么是装饰器模式?

装饰器模式(Decorator Pattern) 是一种结构型设计模式,用于动态地为对象添加额外功能。装饰器模式的核心思想是通过组合而非继承来扩展对象的功能,遵循开闭原则(对扩展开放,对修改关闭)。

核心角色:

  1. 组件接口(Component):定义对象和装饰器的通用接口

  2. 具体组件(Concrete Component):实现基本功能的原始对象

  3. 装饰器基类(Decorator):持有组件引用并实现组件接口

  4. 具体装饰器(Concrete Decorator):添加具体扩展功能

装饰器模式结构图


二、适用场景

  • ✅ 需要动态添加/撤销对象功能

  • ✅ 不适合使用继承扩展功能

  • ✅ 需要组合多种扩展功能

  • ✅ 需要遵循开闭原则


三、PHP实现方案

1. 基础实现(咖啡加料示例)

interface Coffee {
    public function cost(): float;
    public function description(): string;
}

class SimpleCoffee implements Coffee {
    public function cost(): float {
        return 2.0;
    }

    public function description(): string {
        return "Simple coffee";
    }
}

abstract class CoffeeDecorator implements Coffee {
    protected $coffee;

    public function __construct(Coffee $coffee) {
        $this->coffee = $coffee;
    }

    abstract public function cost(): float;
    abstract public function description(): string;
}

class MilkDecorator extends CoffeeDecorator {
    public function cost(): float {
        return $this->coffee->cost() + 0.5;
    }

    public function description(): string {
        return $this->coffee->description() . ", milk";
    }
}

class SugarDecorator extends CoffeeDecorator {
    public function cost(): float {
        return $this->coffee->cost() + 0.2;
    }

    public function description(): string {
        return $this->coffee->description() . ", sugar";
    }
}

// 使用示例
$coffee = new SimpleCoffee();
$coffee = new MilkDecorator($coffee);
$coffee = new SugarDecorator($coffee);

echo $coffee->description(); // 输出:Simple coffee, milk, sugar
echo $coffee->cost();        // 输出:2.7

2. 进阶实现(带链式调用)

trait DecoratorTrait {
    protected $component;

    public function wrap(Component $component): Component {
        $this->component = $component;
        return $this;
    }
}

class BoldDecorator implements Component {
    use DecoratorTrait;

    public function render(): string {
        return "<b>" . $this->component->render() . "</b>";
    }
}

class ItalicDecorator implements Component {
    use DecoratorTrait;

    public function render(): string {
        return "<i>" . $this->component->render() . "</i>";
    }
}

// 使用示例
$text = new TextComponent("Hello World");
$decoratedText = (new BoldDecorator())->wrap(
    (new ItalicDecorator())->wrap($text)
);
echo $decoratedText->render(); // 输出:<b><i>Hello World</i></b>

四、Go实现方案

1. 基础实现(数据流处理)

package main

import "fmt"

type DataProcessor interface {
    Process(data string) string
}

type BasicProcessor struct{}

func (p *BasicProcessor) Process(data string) string {
    return data
}

type ProcessorDecorator struct {
    processor DataProcessor
}

func (d *ProcessorDecorator) Process(data string) string {
    return d.processor.Process(data)
}

type EncryptDecorator struct {
    ProcessorDecorator
}

func (e *EncryptDecorator) Process(data string) string {
    base := e.ProcessorDecorator.Process(data)
    return "Encrypted(" + base + ")"
}

type CompressDecorator struct {
    ProcessorDecorator
}

func (c *CompressDecorator) Process(data string) string {
    base := c.ProcessorDecorator.Process(data)
    return "Compressed(" + base + ")"
}

// 使用示例
func main() {
    processor := &BasicProcessor{}
    
    // 装饰器组合
    encryptedProcessor := &EncryptDecorator{ProcessorDecorator{processor}}
    compressedEncryptedProcessor := &CompressDecorator{ProcessorDecorator{encryptedProcessor}}

    result := compressedEncryptedProcessor.Process("sensitive data")
    fmt.Println(result) // 输出:Compressed(Encrypted(sensitive data))
}

2. 进阶实现(HTTP中间件)

package main

import "fmt"

type Handler func(string)

type Middleware func(Handler) Handler

func LoggingMiddleware(next Handler) Handler {
    return func(req string) {
        fmt.Println("Logging request:", req)
        next(req)
    }
}

func AuthMiddleware(next Handler) Handler {
    return func(req string) {
        fmt.Println("Authenticating...")
        next(req)
    }
}

func main() {
    handler := func(req string) {
        fmt.Println("Processing request:", req)
    }

    // 装饰器链
    decoratedHandler := LoggingMiddleware(
        AuthMiddleware(handler),
    )

    decoratedHandler("GET /api/data")
    // 输出:
    // Logging request: GET /api/data
    // Authenticating...
    // Processing request: GET /api/data
}

五、关键实现差异对比

特性

PHP

Go

接口实现

显式implements关键字

隐式接口实现

装饰器组合方式

通过构造函数注入

通过结构体嵌入

链式调用

支持方法链

需手动组合装饰器

类型系统

强类型需显式声明

类型推断简化代码

中间件实现

通过类实现

通过函数闭包实现


六、模式优缺点分析

👍 优点:

  • 动态扩展功能:运行时添加/移除功能

  • 避免继承爆炸:通过组合实现灵活扩展

  • 遵循开闭原则:无需修改已有代码

  • 功能组合灵活:支持任意顺序组合装饰器

👎 缺点:

  • 增加代码复杂度:引入多个小类

  • 调试困难:多层装饰可能难以追踪

  • 初始化复杂:多层装饰器嵌套初始化


七、实际应用案例

1. Web中间件

// PHP中间件示例
$app = new App();
$app->addMiddleware(new AuthMiddleware());
$app->addMiddleware(new LoggingMiddleware());
$app->handleRequest();

2. 数据流处理

// Go数据流处理
processor := NewBaseProcessor()
processor = NewEncryptDecorator(processor)
processor = NewCompressDecorator(processor)
result := processor.Process(data)

3. GUI组件装饰

// PHP UI组件示例
$textBox = new TextBox();
$textBox = new BorderDecorator($textBox);
$textBox = new ScrollDecorator($textBox);
$textBox->render();

八、与代理模式的区别

装饰器模式

代理模式

目的

动态添加功能

控制对象访问

关注点

功能扩展

访问控制/延迟加载

对象关系

装饰器与组件类型相同

代理与目标对象类型相同

初始化时机

客户端显式组合装饰器

代理通常自行实例化目标对象


九、总结

装饰器模式是动态扩展对象功能的利器,通过组合而非继承的方式,实现了灵活的功能扩展。无论是PHP的类装饰器还是Go的函数式中间件,装饰器模式都能显著提升代码的可维护性和扩展性。

在下一篇文章中,我们将探讨 外观模式 及其在简化复杂系统接口中的应用。敬请期待!


下一篇预告:设计模式系列(十)——外观模式:复杂系统的简化之门

License:  CC BY 4.0