装饰器模式是一种结构型设计模式,用来动态地给一个对象增加一些额外的职责。就增加对象功能来说,装饰器模式比生成子类实现更为灵活。装饰器模式的别名为包装器(Wrapper),与适配器模式的别名相同,但它们适用于不同的场合。
Decorator is a structural design pattern, that can be used to dynamically add some additional responsibilities to anobject. In terms of adding object functionality, the decorator pattern is more flexible than generating subclass implementations. The alias for the decorator pattern is "wrapper", which is the same as the alias for the adapter pattern, but they are suitable for different situations.
结构设计
装饰器模式包含如下角色:
Component: 抽象构件,定义一个对象接口,用来动态地给一个对象增加一些额外的职责
ConcreteComponent: 具体构件,实现一个对象接口
Decorator: 抽象装饰类,拥有一个指向被封装对象的引用成员变量。装饰类会将所有操作委派给被封装的对象。
ConcreteDecorator: 具体装饰类,定义了可动态添加到抽象构件的具体行为。具体装饰类会重写装饰基类的方法,并在调用父类方法之前或之后进行额外的行为。
装饰器模式类图表示如下:
伪代码实现
接下来将使用代码介绍下装饰器模式的实现。
// 1、抽象构件,定义一个对象接口,用来动态地给一个对象增加一些额外的职责
public interface Component {void operation();
}
// 2、具体构件,实现一个对象接口
public class ConcreteComponent implements Component {@Overridepublic void operation() {System.out.println("do some thing in the concrete component instance");}
}
// 3、抽象装饰类,拥有一个指向被封装对象的引用成员变量。装饰类会将所有操作委派给被封装的对象
public class Decorator implements Component {private Component component = null;public Decorator(Component component) {this.component = component;}@Overridepublic void operation() {this.component.operation();}
}
// 4、具体装饰类,定义了可动态添加到抽象构件的具体行为。具体装饰类会重写装饰基类的方法,并在调用父类方法之前或之后进行额外的行为
public class ConcreteDecorator extends Decorator {public ConcreteDecorator(Component component) {super(component);}@Overridepublic void operation() {super.operation();afterOperation();}private void afterOperation() {System.out.printf("do some thing after operation in the concrete decorator");}
}
// 5、客户端调用
public class DecoratorClient {public void test() {// (1) 声明接口并实例化组件Component component = new ConcreteComponent();// (2) 调用组件方法(装饰前)component.operation();// (3) 实例化具体装饰器并对组件进行装饰component = new ConcreteDecorator(component);// (4) 调用组件方法(装饰后)component.operation();}
}
适用场景
在以下情况可以考虑使用装饰器模式:
(1) 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。
(2) 需要动态地给一个对象增加功能,这些功能也可以动态地被撤销。
装饰器能将业务逻辑组织为层次结构,开发者可为各层创建一个装饰,在运行时将各种不同逻辑组合成对象。由于这些对象都遵循通用接口,客户端代码能以相同的方式使用这些对象。
(3) 当不能采用继承的方式对系统进行扩充或者采用继承不利于系统扩展和维护时。不能采用继承的情况主要有两类:第一类是系统中存在大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长;第二类是因为类定义不能继承(如final类)
说明:一般有两种方式可以实现给一个类或对象增加行为:
(1) 继承机制,使用继承机制是给现有类添加功能的一种有效途径,通过继承一个现有类可以使得子类在拥有自身方法的同时还拥有父类的方法。但是这种方法是静态的,用户不能控制增加行为的方式和时机。
(2) 关联机制,即将一个类的对象嵌入另一个对象中,由另一个对象来决定是否调用嵌入对象的行为以便扩展自己的行为,我们称这个嵌入的对象为装饰器(Decorator)
装饰模式以对客户透明的方式动态地给一个对象附加上更多的责任,换言之,客户端并不会觉得对象在装饰前和装饰后有什么不同。装饰模式可以在不需要创造更多子类的情况下,将对象的功能加以扩展。这就是装饰模式的模式动机。
优缺点
装饰器模式有以下优点:
(1) 符合开闭原则。具体构件类与具体装饰类可以独立变化,用户可以根据需要增加新的具体构件类和具体装饰类,在使用时再对其进行组合,原有代码无须改变,符合“开闭原则”。
(2) 符合单一职责原则。开发者可以将实现了许多不同行为的一个大类拆分为多个较小的类。
(3) 提高了代码的可扩展性和灵活性。装饰器模式与继承关系的目的都是要扩展对象的功能,但是装饰器模式可以提供比继承更多的灵活性,可以在不创建新子类的前提下,扩展对象的行为。
(4) 可以通过一种动态的方式来扩展一个对象的功能,通过配置文件可以在运行时选择不同的装饰器,从而实现不同的行为。
(5) 通过使用不同的具体装饰类以及这些装饰类的排列组合,可以创造出很多不同行为的组合。可以使用多个具体装饰类来装饰同一对象,得到功能更为强大的对象。
但是装饰器模式也存在以下缺点:
(1) 代码复杂度上升。使用装饰模式进行系统设计时将产生很多小对象,这些对象的区别在于它们之间相互连接的方式有所不同,而不是它们的类或者属性值有所不同,同时还将产生很多具体装饰类。这些装饰类和小对象的产生将增加系统的复杂度,加大学习与理解的难度。
(2) 装饰器模式比继承更加灵活,也同时意味着装饰器模式比继承更加易于出错,排错也很困难,对于多次装饰的对象,调试时寻找错误可能需要逐级排查,较为烦琐。
参考
《设计模式:可复用面向对象软件的基础》 Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides 著 李英军, 马晓星 等译
https://design-patterns.readthedocs.io/zh_CN/latest/structural_patterns/decorator.html 装饰器模式
https://refactoringguru.cn/design-patterns/decorator 装饰器模式
https://www.runoob.com/design-pattern/decorator-pattern.html 装饰器模式
https://www.cnblogs.com/adamjwh/p/9036358.html 简说设计模式——装饰模式
https://blog.csdn.net/ShuSheng0007/article/details/88780036 秒懂设计模式之装饰者模式