装饰模式
# 装饰模式
# 一、装饰模式
原理:装饰模式是一种结构型设计模式, 允许你通过将对象放入包含行为的特殊封装对象中来为原对象绑定新的行为。
优缺点
- 1 优点
- 职责单一原则:通过将功能划分到不同的装饰类中,可以保持类的单一职责,减少类的复杂性。
- 动态扩展对象功能:可以在运行时动态地添加或删除职责,而无需修改类的定义或使用继承。
- 灵活性:可以根据需要组合多个装饰对象,以不同的方式增强对象的功能,从而提供高度的灵活性和复用性。
- 透明性:客户端可以透明地使用装饰对象,装饰对象和原始对象具有相同的接口。
- 避免类爆炸:相比于通过继承来扩展功能,装饰模式避免了因多重功能扩展而导致的类爆炸问题(即继承层次过于复杂)。
- 2 缺点
- 产生很多小对象:使用装饰模式会产生许多小对象,这些对象之间相互依赖,增加了系统的复杂性,可能会影响性能。
- 调试困难:由于功能是通过多个装饰类叠加实现的,调试和排查问题变得更加困难,因为需要了解装饰链中每个装饰类的行为。
- 违反开闭原则:虽然装饰模式本身符合开闭原则,但如果需要在中途插入新的装饰类,则需要修改现有的装饰链,可能违反开闭原则。
- 依赖关系复杂:装饰类之间的依赖关系可能变得复杂,特别是在多个装饰类组合使用时,需要仔细管理这些依赖关系。
适用场景
- 功能扩展:当你希望在不改变类文件或使用继承的情况下,扩展一个类的功能时。例如,在一个图形编辑器中,为基本的图形类添加边框、阴影、颜色等不同的装饰。
- 职责分配:当需要将一个类中的多种职责分配到多个类中,以避免职责过重的情况时。例如,邮件系统中,可以在发送邮件之前增加加密、压缩等操作。
- 动态功能添加:当需要在运行时动态地添加功能时。例如,在网络请求中,可以在请求发出前动态添加日志记录、缓存处理等功能。
- 细粒度控制:当需要通过组合方式控制类的行为时。例如,在用户界面组件中,可以通过不同的装饰类,动态添加滚动条、边框、颜色等。
- 可撤销操作:当需要能够撤销添加的功能时。例如,在文本编辑器中,可以通过装饰模式实现撤销和重做操作。
# 二、装饰模式基本代码
Component类
abstract class Component { public abstract void operation(); }
1
2
3ConcreteComponent类
class ConcreteComponent extends Component { @Override public void operation() { System.out.println("ConcreteComponent operation"); } }
1
2
3
4
5
6Decorator类
abstract class Decorator extends Component { protected Component component; public Decorator(Component component) { this.component = component; } @Override public void operation() { if(component != null){ component.operation(); } } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14具体装饰类
class ConcreteDecoratorA extends Decorator { public ConcreteDecoratorA(Component component) { super(component); } @Override public void operation() { super.operation(); addedBehavior(); } private void addedBehavior() { System.out.println("ConcreteDecoratorA added behavior"); } } class ConcreteDecoratorB extends Decorator { public ConcreteDecoratorB(Component component) { super(component); } @Override public void operation() { super.operation(); addedBehavior(); } private void addedBehavior() { System.out.println("ConcreteDecoratorB added behavior"); } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31客户端代码
public class Client { public static void main(String[] args) { Component component = new ConcreteComponent(); Component decoratorA = new ConcreteDecoratorA(component); Component decoratorB = new ConcreteDecoratorB(decoratorA); decoratorB.operation(); // 执行装饰后的操作 } }
1
2
3
4
5
6
7
8
9
# 三、实现方式
确保业务逻辑可用一个基本组件及多个额外可选层次表示。
找出基本组件和可选层次的通用方法。 创建一个组件接口并在其中声明这些方法。
创建一个具体组件类, 并定义其基础行为。
创建装饰基类, 使用一个成员变量存储指向被封装对象的引用。 该成员变量必须被声明为组件接口类型, 从而能在运行时连接具体组件和装饰。 装饰基类必须将所有工作委派给被封装的对象。
确保所有类实现组件接口。
将装饰基类扩展为具体装饰。 具体装饰必须在调用父类方法 (总是委派给被封装对象) 之前或之后执行自身的行为。
客户端代码负责创建装饰并将其组合成客户端所需的形式。
编辑 (opens new window)