装饰模式:动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比直接修改子类更加灵活。
装饰模式 Decorator
:也称为包装模式 Wrapper Pattern
,常见于给某个对象添加功能而不是整个类。装饰模式可以修改对象的功能,而不用修改子类代码。代码中如果看到 Wrapper
结尾的类,通常是用了装饰模式的设计思路。
装饰模式通常用于动态和透明的扩展类的功能,特别是当系统维护中需要添加新功能,而这个功能是需要向旧类中添加新代码,而这个功能并不是旧类的主要职责或者核心功能。在这种场景下,使用装饰模式添加一个装饰类,在不破坏原有代码的基础上,动态的给对象添加或修改功能。
装饰模式 Decorator
类图结构
结构解析
Component
抽象类,定义公共方法。ConcreteComponent
实现类,实现该方法。Decorator
抽象类,也是装饰类,类内部会指向一个Component
实现类,形成组合关系,具体的operation
都是传入的Component
来实现的。ConcreteDecorator
实现类,除了调用ConcreteComponent
对应的方法,通常会修改或增加功能。
示例
1 | // 1. Component |
Android
中经典的装饰模式
Android
中的 Context/ContextWraaper
就是经典的装饰模式。
类图结构
类图解析
Context
抽象类,定义了所有的公共方法。ContextImpl
实现类,实现了所有的方法。ContextWrapper
包装类,也是抽象类,使用组合结构引用了ContextImpl
。Activity
包装类实现类,Activity, Service, Application
都继承了ContextWrapper
,这些子类动态添加或修改了ContextImpl
的部分方法。
总结
装饰模式很容易和桥接模式、代理模式混淆,我们看下他们之间的区别以及装饰模式的优缺点。
装饰模式和桥接模式的区别
类图结构有较大区别,从对比图中可以看出:
- 结构维度
桥接模式是不同维度的分类,属于平行结构;装饰模式是继承结构,在继承的基础上修改功能。 - 是否继承
桥接模式的两种维度没有继承关系,仅仅是组合关系(松耦合);而装饰模式除了组合还必须是继承关系(紧耦合),也就是Decorator
继承并组合了Component
。 - 方法名是否一致
桥接模式仅仅需要组合,所以方法名一般不同;装饰模式因为带有继承关系,所以装饰时重写方法,方法名相同。
装饰模式和代理模式的区别
- 类图结构基本一致
override
重写方法后的侧重点不一样
装饰器模式关注于在一个对象上动态的添加或修改方法;代理模式关注于控制对对象的访问,对是否执行实现类有决定权。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16// 1. 装饰器模式
public void operation() {
impl.operation();
addBehavior();
}
// 2. 代理模式
public void operation() {
if (hasOption()){
impl.operation();
} else {
System.out.println("不符合选项。");
}
}
装饰模式和代理模式非常非常像,唯一的区别在与侧重点不一样:装饰模式侧重于修改功能,代理模式侧重于控制访问。
装饰模式优缺点
- 优点
可以通过一种动态的方式来扩展一个对象的功能,具体构件类与具体装饰类可以独立变化,原有代码无须改变,符合“开闭原则”。 - 缺点
使用装饰模式进行系统设计时将产生很多小对象,这些对象的区别在于它们之间相互连接的方式有所不同,而不是它们的类或者属性值有所不同,同时还将产生很多具体装饰类。
参考文档
- 大话设计模式
Android
源码设计模式解析与实战- 装饰模式和代理模式区别
- 装饰模式