DECORATOR 装饰模式
1、 意图
动态地给一个对象添加一些额外的职责。就添加功能来说,Decorator模式就比生成子类更灵活。
2、 适用性
- 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。
- 处理那些可以撤销的职责。
- 当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。
3、 结构
4、 参与者
Component
——定义一个对象接口,可以给这些对象动态地添加职责。
ConcreteComponent
——定义一个对象,可以给这些对象添加一些职责。
Decorator
——维持一个指向Component对象的指针,并定义一个与Component接口一致的接口。
ConcreteDecorator
——向组件添加职责。
5、 协作
Decorator将请求转发给它的Component对象,并有可能在转发请求前后执行一些附加的动作。
6、 效果
Decorator模式至少有两个主要优点和两个缺点:
1) 比静态继承更灵活。与对象的静态继承(多重继承)相比,Decorator模式提供了更加灵活的向对象添加职责的方式。可以用添加和分离的方法,用装饰在运行时刻添加或删除职责。
2) 避免在层次结构高层的类有太多的特征。Decorator模式提供了一种“即用即付”的方法来添加职责。它并不试图在一个复杂的可定制的类中支持所有可预见的特征,相反,你可以定义一个简单的类,并且用Decorator类给它逐渐地添加功能。
3) Decorator与它的Component不一样。Decorator是一个透明的包装。如果我们从对象标识的观点出发,一个被装饰了的组件与这个组件是有差别的,因此,使用装饰时不应该依赖对象标识。
4) 有很多的小对象。采用Decorator模式进行系统设计往往会产生许多看上去类似的小对象,这些对象仅仅在他们互相连接的方式上有所不同,而不是它们的类或是它们的属性值有所不同。
7、 实现
1) 接口的一致性。装饰对象的接口必须与它所装饰的Component的接口是一致的,因此,所有的ConcreteDecorator类必须有一个公共的父类。
2) 省略抽象的Decorator类;当你仅需要添加一个职责时,没有必要定义抽象Decorator类。
3) 保持Component类的简单性。为了保证接口的一致性,组件和装饰必须有一个公共的Component父类。因此保持这个类的简单性很重要;即,它应集中与定义接口而不是存储数据。
4) 改变对象外壳与改变对象内核;我们可以将Decorator看作一个对象的外壳,它可以改变对象的行为。另一种方法是改变对象的内核。
8、 代码示例
Component
package com.examples.pattern.decorator;
/**
* 组件对象的接口,可以给这些对象动态地添加职责
*/
public abstract class Component {
public abstract void operation();
}
ConcreteComponent
package com.examples.pattern.decorator;
/**
* 具体实现组件对象接口的对象
*/
public class ConcreteComponent extends Component {
@Override
public void operation() {
System.out.println("operation....");
}
}
Decorator
package com.examples.pattern.decorator;
/**
* 装饰器接口,维持一个指向组件对象的接口对象,并定义一个与组件接口一致的接口
*/
public abstract class Decorator extends Component {
protected Component component;
/**
* 构造方法,传入组件对象
*
* @param component
* 组件对象
*/
public Decorator(Component component) {
this.component = component;
}
@Override
public void operation() {
// 转发请求给组件对象,可以在转发前后执行一些附加动作
component.operation();
}
}
ConcreteDecorator
package com.examples.pattern.decorator;
/**
* 装饰器的具体实现对象,向组件对象添加职责
*/
public class ConcreteDecoratorA extends Decorator {
public ConcreteDecoratorA(Component component) {
super(component);
}
/**
* 添加的状态
*/
private String addedState;
public String getAddedState() {
return addedState;
}
public void setAddedState(String addedState) {
this.addedState = addedState;
}
public void operation() {
super.operation();
System.out.println("ConcreteDecoratorA :" + addedState);
}
}
package com.examples.pattern.decorator;
/**
* 装饰器的具体实现对象,向组件对象添加职责
*/
public class ConcreteDecoratorB extends Decorator {
public ConcreteDecoratorB(Component component) {
super(component);
}
/**
* 添加的状态
*/
private String addedState;
public String getAddedState() {
return addedState;
}
public void setAddedState(String addedState) {
this.addedState = addedState;
}
public void operation() {
super.operation();
System.out.println("ConcreteDecoratorB :" + addedState);
}
}
Client
package com.examples.pattern.decorator;
public class Client {
/**
* @param args
*/
public static void main(String[] args) {
ConcreteComponent cc = new ConcreteComponent();
ConcreteDecoratorA cda = new ConcreteDecoratorA(cc);
ConcreteDecoratorB cdb = new ConcreteDecoratorB(cc);
cda.setAddedState("this is a");
cdb.setAddedState("this is b");
cda.operation();
cdb.operation();
}
}
9、 相关模式
Adapter模式:Decorator模式不同于Adapter模式,因为装饰仅改变对象的职责而不改变它的接口;而适配器将给对象一个全新的接口。
Composite模式:可以将装饰视为一个退化的、仅有一个组件的组合。然而,装饰仅给对象添加一些额外的职责——它的目的不在于对象聚集。
Strategy模式:用一个装饰你可以改变对象的外表;而Strategy模式使得你可以改变对象的内核。这是改变对象的两种途径。