装饰者模式的定义
装饰模式(Decorator Pattern) 也称包装模式(Wrapper Pattern),是结构型设计模式之一,使用一种对客户端透明的方式来动态地拓展对象的功能,同时它也是继承关系的一种替代方案之一。
通过装饰者模式可以动态地给一个对象添加一些额外的职责。就增加功能而言,装饰模式相比生成子类更灵活。因为它装饰者持有一个被装饰者的引用,因此可以方便地调用具体被装饰者对象中的方法,因此可以在不破坏原类层次结构的情况下为类增加一些功能,我们只需要在被装饰者对象的相应方法前后增加相应的功能逻辑即可。
使用场景
需要透明且动态地拓展类的功能时。
UML 类图

- Component 抽象组件
- 可以是接口或者抽象类,充当一个被装饰的原始对象。(在该模式中位于继承结构的顶部,大家都直接/间接地继承它)
- ConcreteComponent 组件具体实现类
- 该类是 Component 类的具体实现,也是我们装饰的具体对象。
- Decorator 抽象装饰者
- 继承自 Component 并且必须持有一个指向 Component 的引用
- 通常会在其方法中调用 ConcreteComponent 的方法。
- 如果装饰逻辑单一,可以直接省略该类,直接写一个具体的装饰者对象即可。
- ConcreteDecoratorA,B,C
- 继承自 Decoration, 在父类对 Component 的方法调用基础上上,增加自己的一些功能。(通常都是在基础方法执行前或者后调用自己新增的方法)
使用时经常会把 ComponentImpl 或者说 ConcreteComponent 传入给具体的 Decorator。
|
|
Android 源码中的模式实现

角色简介:
- Context :抽象组件
- ComtextImpl :Context 的具体实现类
- ContextWrapper :装饰者的父类(其中的所有方法都只是调用了 ContextImpl 中对应的方法)
- ContextThemeWrapper :继承自 ContextWrapper 的装饰者
- Activity :继承自 ContextThemeWrapper 的装饰者
我们以常用的方法为例,看看装饰者模式在其中的具体实现方式
|
|
从以上的代码中可以看出,ContextWrapper 作为装饰者的父类,持有 Context 的引用 mBase(mBase 的实际类型为 ContextImpl),其中的所有方法都只是调用了 ContextImpl 中对应的方法。
|
|
可以看到,ContextImpl 中提供了具体的方法实现。
ContextWrapper 的子类,例如 Activity 会根据需要对具体方法的实现进行装饰或者修改。
比如 startActivity() 方法,Activity 没有使用被装饰者的实现,而是自己实现了一套逻辑。
|
|
ContextImpl 的创建
从上面解析中我们知道 Context 的实现中使用了装饰者模式也知道了 ContextImpl 是 Context 具体实现类,但是 ContextImpl 是在上面地方被初始化的呢?
因为 Activity 启动之后我们便可以调用 Context 中的方法了,我们猜想 ContextImpl 是在 Activity 创建过程中初始化的。
对 Android Framework 层有所了解同学应该知道 Activity 是由 AMS 管理的,AMS 会通过调用 ApplicationThread 与间接地控制 Activity。 ApplicationThread 的 scheduleXxx 方法中会调用 sendMessage 方法将相应的 Message 发送给 H,H 根据不同的 Message 调用 ActivityThread 中相应的 handleXxx 方法。
ActivityThread#H
|
|
当需要启动新的 Activity 时,ApplicationThread 的 scheduleLaunchActivity 方法会先被调用,该方法会通过 H 调用 handleLaunchActivity 方法,而 handleLaunchActivity 方法又会调用 performLaunchActivity 方法。
ActivityThread#performLaunchActivity
|
|
ActivityThread#createBaseContextForActivity
|
|
ContextImpl#createActivityContext()
|
|
经过上面的分析,我们可以得出结论,Activity 的 Context 是在 performLaunchActivity 方法中通过调用 createBaseContextForActivity 初始化的。在 createBaseContextForActivity 方法中,通过调用 ContextImpl 的静态方法 createActivityContext 创建 获取一个 ContextImpl 的实例对象,并通过 setOuterContext 方法将两者建立关联。
总结
学过代理模式的同学可能觉得装饰模式与代理模式有点像(因为同样持有引用)。但是既然是它们是两个不同的设计模式,先看看它们各自的定义。
装饰模式:以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案;
代理模式:给一个对象提供一个代理对象,并由代理对象来控制对原有对象的引用;
光看定义可能还是比较模糊。二者区别在哪里呢?
- 装饰模式应该为所装饰的对象增强功能
- 代理模式对代理的对象施加控制,但不对对象本身的功能进行增强。
可以简单地理解为:你在一个地方写装饰,大家就知道这是在增加功能,你写代理,大家就知道是在限制。
参考资料与学习资源推荐
- 《Android 源码设计模式解析与实战》