天天看点

[设计模式笔记]二. 结构型模式--10.Decorator模式(装饰模式)(一)一. 意图二. 适用性三. 模式结构四. 角色说明五. 说明六. 我的理解七. 相关模式

Decorator(装饰)模式(对象结构型模式)

一. 意图

动态地给一个对象添加一些额外的职责. 就增加功能来说, Decorator模式相比生成子类更为灵活.

二. 适用性

1. 在不影响其他对象的情况下, 以动态, 透明的方式给单个对象添加职责.

2. 处理那些可以撤消的职责.

3. 当不能采用生成子类的方法进行扩充时. 一种情况是, 可能有大量独立的扩展, 为支持每一种组合将产生大量的子类, 使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏, 或类定义不能用于生成子类.

三. 模式结构

[设计模式笔记]二. 结构型模式--10.Decorator模式(装饰模式)(一)一. 意图二. 适用性三. 模式结构四. 角色说明五. 说明六. 我的理解七. 相关模式

图1 

四. 角色说明

Component

—定义一个对象接口,可以给这些对象动态地添加职责。

ConcreteComponent

—定义一个对象,可以给这个对象添加一些职责。

Decorator

—维持一个指向Component对象的指针, 并定义一个与Component接口一致的接口.

ConcreteDecorator

—向组件添加职责

Decorator将请求转发给它的Component对象, 并有可能在转发请求前后执行一些附加的动作.

五. 说明

对一个已经封装好的功能增加功能, 因为已经封装好了, 你不可能在它的内部进行修改. 现在就有两种方式: 

1. 使用继承, 生成一个该功能的子类. 这个子类的要求肯定是要实现父类的接口(父类公开出来的方法).(因为父类已经在用了).

然后对父类对应的方法进行功能扩展.(在父类的方法里面你喜欢怎样就怎样了).

2. 生成一个类, 该类包含该原功能类的对象. 这个类同样实现原功能类的接口.(新类中对应的接口调用对象对应的接口).

(新类与功能类继承与同一接口, 这样原来的用户就不需要改动代码.)(这就是Decorator模式了)

使用Decorator模式时应注意以下几点:

1. 接口的一致性 装饰对象的接口必须与它所装饰的Component的接口是一致的, 因此,所有的ConcreteDecorator类必须有一个公共的父类.

2. 没有抽象的Decorator类, 因为你常常需要处理现存的类层次结构而不是设计一个新系统, Decorator与ConcreteComponent位于同一类层次即可(继承于同一父类). 

3. 保持Component类的简单性 为了保证接口的一致性, 组件和装饰必须有一个公共的Component父类. 因此保持Component类的简单性是很重要的: 即它应集中于定义接口而不是存储数据. 对数据表示的定义应延迟到子类中, 否则Component类会变得过于复杂和庞大, 因而难以大量使用。赋予Component太多的功能也使得,具体的子类有一些它们并不需要的功能的可能性大大增加。

4. 改变对象外壳与改变对象内核, 我们可以将Decorator看作一个对象的外壳, 它可以改变这个对象的行为. 另外一种方法是改变对象的内核. 例如Strategy模式就是一个用于改变内核的很好的模式.

六. 我的理解

1. 有一个类, 你不能改变它的内部实现, 但是需要扩展它的功能.你可以使用一个新类, 新类包含一个原类的对象, 在调用对象的方法前后扩展它的功能. 有一个问题, 原类已经再使用了, 它的接口已经被客户使用了. 我们扩展它的功能的前提是尽量的让客户少改代码, 少改变. 如果原类的功能方法不是继承接口的(原类没有父类, 或者说原类提供给客户的方法不是接口), 那Decorator模式无法使用的. ConcreteComponent与Decorator必须有相同的接口(要扩展功能所对应的那个接口).

[设计模式笔记]二. 结构型模式--10.Decorator模式(装饰模式)(一)一. 意图二. 适用性三. 模式结构四. 角色说明五. 说明六. 我的理解七. 相关模式

图2

2. Decorator中包含一个ConcreteComponent对象, Decorator::Operation中调用ConcreteComponent::Operation.

而ConcreteDecorator::Operation调用Decorator::Operation (可以看到ConcreteComponent与ConcreteDecorator被Decorator隔开了解耦了).

这样隔开, 效果非常明显在类层次上, 我可以横向的扩展ConcreteComponent的功能(增加ConcreteDecorator类). 如果使用纵向扩展(类继承), 一条长长的类继承链, That's not a good idea.

3. Decorator中定义的是一个Component指针, 而不是一个ConcreteComponent指针, 也就是Decorator不是针对某个ConcreteComponent类扩展, 而是可以针对所有的ConcreteComponent来扩展.(这一点可以区分Proxy代理模式: 它就是针对某个类的)

4. ConcreteDecorator::Operation中你可以根据你的需求随便修改, 甚至Decorator::Operation你也可以不调用, 看需求吧.

七. 相关模式

1. Adapter模式:Decorator模式不同于Adapter模式, 因为装饰仅改变对象的职责而不改变它的接口; 而适配器将给对象一个全新的接口.

2. Composite模式: 可以将装饰视为一个退化的, 仅有一个组件的组合. 然而, 装饰仅给对象添加一些额外的职责—它的目的不在于对象聚集.

3. Strategy模式: 用一个装饰你可以改变对象的外表; 而Strategy模式使得你可以改变对象的内核. 这是改变对象的两种途径.

继续阅读