装饰模式/Decorator
意图/适用场景:
装饰模式将更多的功能动态地附加到一个对象上。对功能扩展而言,装饰模式提供了一个灵活的、可以替代“继承”的选择。
装饰模式通过被装饰类的一个子类的实例,把客户端的调用委派到被装饰类。
在以下情况下应当使用装饰模式:
- 需要扩展一个类的功能,或给一个类增加责任。
- 需要动态地给一个对象增加功能,这些功能可以再动态地撤销。
- 需要增加同一些基本功能的排列组合而产生的非常大量的功能,从而使继承关系变得不现实。
UML:
参与者:
- Component: 一个抽象接口,规范了准备接收附加功能/责任的对象。
- Concrete Component: 定义一个将要接收附加功能/责任的类。
- Decorator: 持有一个Component对象的实例,并且实现Component接口。在实现的接口方法中,调用Component对象的相应方法来实现功能。
- Concrete Decorator: 负责给Component对象附加功能。
要点:
Decorator模式的设计思想在于,系统中会有很多个Concrete Decorator,而每一个Concrete Decorator可以把其它的Concrete Decorator作为自己的基础,在其之上增加一些功能。
而这些功能扩展是动态的,而且是多变的,各种Concrete Decorator可以随意地互相组合。这不同于基于继承的扩展,后者是静态的、不变的。
优点与缺点:
- 装饰模式与继承关系的目的都是扩展对象的功能,但装饰模式可以提供更多的灵活性。
- 通过使用不同的Concrete Decorator以及它们的组合,可以创造出很多不同行为的组合。
- 使用装饰模式比使用继承关系需要的类数目更少,但对象的数目会更多,而且对象间的组合关系会更加复杂。
扩展:
看下面的这幅对象关系图。这是Decorator模式的典型用法,对象的数量还可以更多,层数也可以更多。在每一层,Concrete Decorator对下一层的功能做一点扩展,最后实现了庞大的功能集合。 也可以这样理解,Concrete Component被一层一层的Concrete Decorator所包裹,所以这种模式也常常被称为“包裹”模式。
示例代码:
[java]
// Source code from file:Component.java
packagedesignPatterns.Decorator;
publicinterface Component {
publicvoid sampleOperation();
}
// Source code from file:ConcreteComponent.java
packagedesignPatterns.Decorator;
publicclass ConcreteComponent implements Component {
publicvoid sampleOperation() {
System.out.println("ConcreteComponent.sampleOperation()");
}
}
// Source code from file:ConcreteDecoratorA.java
packagedesignPatterns.Decorator;
publicclass ConcreteDecoratorA extends Decorator {
privateDecorator decorator;
publicConcreteDecoratorA() {
this.decorator= null;
}
publicConcreteDecoratorA(Decorator decorator) {
this.decorator= decorator;
}
publicvoid sampleOperation() {
System.out.println("ConcreteDecoratorA.sampleOperation()");
if(null != decorator)
decorator.sampleOperation();
}
}
// Source code from file:ConcreteDecoratorB.java
packagedesignPatterns.Decorator;
publicclass ConcreteDecoratorB extends Decorator {
privateDecorator decorator;
publicConcreteDecoratorB() {
this.decorator= null;
}
publicConcreteDecoratorB(Decorator decorator) {
this.decorator= decorator;
}
publicvoid sampleOperation() {
System.out.println("ConcreteDecoratorB.sampleOperation()");
if(null != decorator)
decorator.sampleOperation();
}
}
// Source code from file:Decorator.java
packagedesignPatterns.Decorator;
publicclass Decorator implements Component {
privateComponent component;
publicDecorator() {
// make a default component;
component =new ConcreteComponent();
}
publicDecorator(Component component) {
this.component= component;
}
publicvoid sampleOperation() {
System.out.println("Decorator.sampleOperation()");
component.sampleOperation();
}
}
// Source code from file:User.java
packagedesignPatterns.Decorator;
publicclass User {
publicstatic void main(String[] args) {
Componentc = new ConcreteComponent();
Decorator decorator =new Decorator(c);
Decorator a =new ConcreteDecoratorA(decorator);
Decorator b =new ConcreteDecoratorB(a);
b.sampleOperation();
System.out.println();
// re-org
b =new ConcreteDecoratorB(decorator);
a =new ConcreteDecoratorA(b);
a.sampleOperation();
}
}
[/java]