DEV Community

菜皮日记
菜皮日记

Posted on

结构型设计模式-装饰器 Decorator

简介

装饰器模式可以在目标对象原有的基础上,添加其他功能,实现动态增强。

需要明确的是代理模式也有类似的作用,而装饰器模式与代理模式最大的不同在于,装饰器模式下,对目标对象设置增强的权利交给了 client,即 client 先要得到目标对象,之后决定要用哪些装饰器给目标对象增强,一层层嵌套。

具体来说比如 Java 的 IO 操作,一般需要先 new 一个目标对象 FileInputStream,之后将其作为参数传给 BufferedInputStream 即可实现有 buffer 增强功能 InputStream。

装饰器类和被装饰类应该实现同一接口,这样可以保证被装饰器增强后的类的调用方式与之前一直,且支持无限次装饰调用。

装饰器是典型的组合优于继承的例子,试想如果用继承来实现增强的话,每有一个增强项,都需要重写一个类,而支持多种增强项的类则需要继承多次。

角色

  • Component 接口

    定义基本的操作

  • Decorator 装饰器

    实现 Component 接口,增强代码所在

  • Wrappee/Concrete Component 被装饰的原始类

    实现 Component 接口,是被装饰增强的原始类

类图

图中所示,Component 是共有的接口,Concrete Component 是被装饰的类,Concrete Decorators 装饰器类。装饰器类接收 Component 为参数,execute 方法即增强方法。

类图

代码

interface Component
{
    public function operation(): string;
}

class ConcreteComponent implements Component
{
    public function operation(): string
    {
        return "ConcreteComponent";
    }
}

class Decorator implements Component
{
    protected $component;

    public function __construct(Component $component)
    {
        $this->component = $component;
    }

    public function operation(): string
    {
        return $this->component->operation();
    }
}

class ConcreteDecoratorA extends Decorator
{
    public function operation(): string
    {
        return "ConcreteDecoratorA(" . parent::operation() . ")";
    }
}

class ConcreteDecoratorB extends Decorator
{
    public function operation(): string
    {
        return "ConcreteDecoratorB(" . parent::operation() . ")";
    }
}

function clientCode(Component $component)
{
    echo "RESULT: " . $component->operation() . "\n";
}

$simple = new ConcreteComponent();
echo "Client: I've got a simple component:\n";
clientCode($simple);

echo "\n";

$decorator1 = new ConcreteDecoratorA($simple);
$decorator2 = new ConcreteDecoratorB($decorator1);
echo "Client: Now I've got a decorated component:\n";
clientCode($decorator2);
Enter fullscreen mode Exit fullscreen mode

output:

Client: I've got a simple component:
RESULT: ConcreteComponent

Client: Now I've got a decorated component:
RESULT: ConcreteDecoratorB(ConcreteDecoratorA(ConcreteComponent))
Enter fullscreen mode Exit fullscreen mode

Image of Datadog

The Essential Toolkit for Front-end Developers

Take a user-centric approach to front-end monitoring that evolves alongside increasingly complex frameworks and single-page applications.

Get The Kit

Top comments (0)

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay