定义
指在不改变现有对象结构的情况下,动态地给该对象增加一些职责(即增加其额外功能)的模式。
优点:
- 装饰模式与继承关系的目的都是要扩展对象的功能,但是装饰模式可以提供比继承更多的灵活性。继承通过覆盖的方式重写需要扩展的函数,当然也可以通过super.xxx()获取原本的功能,然后在该功能基础上扩展新功能,但它只能增加某一项功能;如果要通过继承实现增加多种功能,那么需要多层继承多个类来实现;而装饰模式可以在原有功能的基础上通过组合来增加新功能,这些新功能已经被封装成一个个独立的装饰类,在运行期间通过搭积木的方式选择装饰类拼凑即可。
- 可以设计出多个不同的具体装饰类,创造出多个不同行为的组合。
缺点:
- 这种比继承更加灵活机动的特性,也同时意味着更加多的复杂性。
- 装饰模式会导致设计中出现许多小类,如果过度使用,会使程序变得很复杂。
- 装饰模式是针对抽象组件(Component)类型编程。但是,如果你要针对具体组件编程时,就应该重新思考你的应用架构,以及装饰者是否合适。当然也可以改变Component接口,增加新的公开的行为,实现“半透明”的装饰者模式。在实际项目中要做出最佳选择
应用场景:
- 需要增强一个对象中某些函数的功能。
- 需要动态地给一个对象增加功能,这些功能可以再动态地撤销。
- 需要增加 由一些基本功能排列组合 而产生的大量功能,从而使继承体系大爆炸。
模式结构:
1.需要被装饰的对象所在的类和装饰类都有一个共同的父类Component,该类中拥有需要添加额外功能的函数:operation();
class ConcreteDecorator {
private Component component;
返回类型 operation(){
// 执行上一层的operation(),并获取返回结果
返回结果 = component.operation();
// 拿到返回结果后,再做额外的处理
处理返回结果
return 返回结果;
}
}
2.ConcreteComponent是需要被装饰的类;Decorator是装饰类。
3.Decorator类中持有被装饰对象的引用,客户端通过setComponent(Component)设置;
4.Decorator类的operation()函数中,执行了被用户set进去的component对象中的operation()函数,也就是首先执行被装饰类原本的功能;
class Decorator() extends Component{
//需要被装饰的对象
private Component component;
//提供给客户端将需要被装饰的对象设置进来
public void setComponent(Component component){
this.component = component;
}
//执行需要被装饰对象原本的operation函数
public void operation(){
this.component.operation();
}
}
Decorator的子类们的operation()函数,拥有被装饰类原本的功能和新需要增加的功能。
class ConcreteDecorator() extends Decorator{
//需要被装饰的对象
private Component component;
//提供给客户端将需要被装饰的对象设置进来
public void setComponent(Component component){
this.component = component;
}
//执行需要被装饰对象原本的operation函数+附加的功能
public void operation(){
//新的功能……………………
super.operation();
//新的功能……………………
}
}
客户端代码:
public static void main(String[] args) {
// 准备好所有装饰类
DecoratorA decoratorA = new DecoratorA();
DecoratorB decoratorB = new DecoratorB();
DecoratorC decoratorC = new DecoratorC();
// 准备好 被装饰的类
Component component = new Component();
// 组装装饰类
decoratorC.setComponent(decoratorB);
decoratorB.setComponent(decoratorA);
decoratorA.setComponent(component);
// 执行
decoratorC.operation();
}
此时,decoratorB对象就是原本需要被装饰的concreteComponent对象,只不过这个对象的operation()函数在原本operation()的基础上增加了ConcreteDecoratorA和ConcreteDecoratorB新的功能。
执行过程:
装饰模式和建造者模式的异同?
相同点:建造者模式和装饰模式都使用了面向切面编程的思想,装饰模式中的装饰类和建造者模式中建造者类的一个个函数都是为被装饰对象附加函数额外功能或为对象中的属性赋值。
不同点:建造者给对象添砖加瓦的顺序是固定的,在Director类中写好的;
而装饰模式中需要添加哪些操作是由客户端决定的。
设计原则
- 多用组合,少用继承。
利用继承设计子类的行为,是在编译时静态决定的,而且所有的子类都会继承到相同的行为。然而,如果能够利用组合的做法扩展对象的行为,就可以在运行时动态地进行扩展。
参考:
(1)柴毛毛大话设计模式——开发常用的设计模式梳理 https://blog.csdn.net/u010425776/article/details/79211117
(2)三分钟理解“装饰模式”——设计模式轻松掌握 https://blog.csdn.net/u010425776/article/details/48245835