设计模式 - 装饰器模式

Posted wwj1992

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式 - 装饰器模式相关的知识,希望对你有一定的参考价值。

装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。
这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。
我通过下面的实例来演示装饰器模式的用法。

 

介绍
意图:动态地给一个对象添加一些额外的职责。就增加功能来说,装饰器模式相比生成子类更为灵活。

 

主要解决:一般的,我们为了扩展一个类经常使用继承方式实现,由于继承为类引入静态特征,并且随着扩展功能的增多,子类会很膨胀。

 

何时使用:在不想增加很多子类的情况下扩展类。

 

如何解决:将具体功能职责划分,同时继承装饰者模式。

 

关键代码:

定义一只猫的接口:

public interface ICat {
    void say();
}

接口的实现:

public class CatComponent implements ICat {
    @Override
    public void say() {
        System.out.println("我是一只猫,喵喵喵喵。");
    }
}

装饰器:当你想给猫添加不同的颜色,于是定义一个修饰器

public abstract class CatDecorator implements ICat {

    protected ICat iCat;

    public CatDecorator(ICat iCat) {
        this.iCat = iCat;
    }
}

定义一个修饰器实现:

public class CatDecoratorComponent extends CatDecorator {

    public CatDecoratorComponent(ICat iCat) {
        super(iCat);
    }

    @Override
    public void say() {
        System.out.println("嘻嘻嘻,装饰一下~~~");
        iCat.say();
        System.out.println("完成~~~");
    }
}

调用测试:

public class CatDecoratorComponentTest {
    @Test
    public void test0(){
        ICat iCat=new CatComponent();
        CatDecorator catDecorator=new CatDecoratorComponent(iCat);
        catDecorator.say();
    }
}

输出:

嘻嘻嘻,装饰一下~~~
我是一只猫,喵喵喵喵。
完成~~~

装饰器和代理模式的区别

对装饰器模式来说,装饰者(Decorator)和被装饰者(Decoratee)都实现一个接口。对代理模式来说,代理类(Proxy Class)和真实处理的类(Real Class)都实现同一个接口。

此外,不论我们使用哪一个模式,都可以很容易地在真实对象的方法前面或者后面加上自定义的方法。

在上面的例子中,装饰器模式是使用的调用者从外部传入的被装饰对象(coffee),调用者只想要你把他给你的对象装饰(加强)一下

而代理模式使用的是代理对象在自己的构造方法里面new的一个被代理的对象,不是调用者传入的。调用者不知道你找了其他人,他也不关心这些事,只要你把事情做对了即可。

装饰器模式关注于在一个对象上动态地添加方法,而代理模式关注于控制对对象的访问。换句话说,用代理模式,代理类可以对它的客户隐藏一个对象的具体信息。

因此当使用代理模式的时候,我们常常在一个代理类中创建一个对象的实例;当使用装饰器模式的时候,我们通常的做法是将原始对象作为一个参数传给装饰器的构造器。

装饰器模式和代理模式的使用场景不一样,比如IO流使用的是装饰者模式,可以层层增加功能。而代理模式则一般是用于增加特殊的功能,有些动态代理不支持多层嵌套。

代理和装饰其实从另一个角度更容易去理解两个模式的区别:代理更多的是强调对对象的访问控制,比如说,访问A对象的查询功能时,

访问B对象的更新功能时,访问C对象的删除功能时,都需要判断对象是否登陆,那么我需要将判断用户是否登陆的功能抽提出来,并对A对象、B对象和C对象进行代理,

使访问它们时都需要去判断用户是否登陆,简单地说就是将某个控制访问权限应用到多个对象上;而装饰器更多的强调给对象加强功能,比如说要给只会唱歌的A对象添加跳舞功能,

添加说唱功能等,简单地说就是将多个功能附加在一个对象上。

所以,代理模式注重的是对对象的某一功能的流程把控和辅助,它可以控制对象做某些事,重心是为了借用对象的功能完成某一流程,而非对象功能如何。

而装饰模式注重的是对对象功能的扩展,不关心外界如何调用,只注重对对象功能加强,装饰后还是对象本身。

总结

对于代理类,如何调用对象的某一功能是思考重点,而不需要兼顾对象的所有功能;对于装饰类,如何扩展对象的某一功能是思考重点,同时也需要兼顾对象的其他功能,因为再怎么装饰,本质也是对象本身,要担负起对象应有的职责,被装饰者的职责一旦增加,作为装饰类也需要有相应的扩展,必然会造成编码的负担。

设计模式本身是为了提升代码的可扩展性,灵活应用即可,不必生搬硬套,非要分出个所以然来,装饰器模式和代理模式的区别也是如此。

 

以上是关于设计模式 - 装饰器模式的主要内容,如果未能解决你的问题,请参考以下文章

编程模式之Go语言如何实现装饰器

设计模式之装饰器模式

装饰器模式

C++装饰器模式的实现

C++装饰器模式的实现

C++装饰器模式的实现