设计模式(11):装饰模式DECORATOR

装饰模式

装饰模式(Decorator Pattern)也叫做包装器(Wrapper)

意图

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


使用场景

以下情况使用Decorator模式:

  • 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。
  • 处理那些可以撤消的职责。
  • 当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。

结构

装饰模式结构如下
ShowImage

  • Component

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

  • ConcreteComponent

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

  • Decorator

    –维持一个指向Component对象的引用,并定义一个与Component接口一致的接口。

  • ConcreteDecorator

    –向Component添加职责。

协作

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

效果

  • 比静态继承更灵活

    与对象的静态继承(多重继承)相比,Decorator模式提供了更加灵活的向对象添加职责的方式。可以用添加和分离的方法,用装饰在运行时刻增加和删除职责。相比之下,继承机制要求为每个添加的职责创建一个新的子类。这会产生许多新的类,并且会增加系统的复杂度。此外,为一个特定的Component类提供多个不同的Decorator类,这就使得你可以对一些职责进行混合和匹配。使用Decorator模式可以很容易地重复添加一个特性,而两次继承类实现非常容易出错。

  • 避免在层次结构高层的类有太多的特征

    Decorator模式提供了一种“即用即付”的方法来添加职责。它并不试图在一个复杂的可定制的类中支持所有可预见的特征,相反,你可以定义一个简单的类,并且用Decorator类给它逐渐地添加功能。可以从简单的部件组合出复杂的功能。这样,应用程序不必为不需要的特征付出代价。同时也更易于不依赖于Decorator所扩展(甚至是不可预知的扩展)的类而独立地定义新类型的Decorator。扩展一个复杂类的时候,很可能会暴露与添加的职责无关的细节。

  • Decorator与它的Component不一样

    Decorator是一个透明的包装。如果我们从对象标识的观点出发,一个被装饰了的组件与这个组件是有差别的,因此,使用装饰时不应该依赖对象标识。

  • 有许多小对象

    采用Decorator模式进行系统设计往往会产生许多看上去类似的小对象,这些对象仅仅在他们相互连接的方式上有所不同,而不是它们的类或是它们的属性值有所不同。尽管对于那些了解这些系统的人来说,很容易对它们进行定制,但是很难学习这些系统,排错也很困难。


装饰模式实现(Implement)

案例

现在Shape接口有draw()方法,Circle类和Rectangle类实现了这个接口并实现了draw()方法,现在要给Shape类增加背景颜色,使用ShapeDecorator类对Shape进行包装,并且在RedShapeDecorator类中继承实现增加红色背景。

代码实现

Shape类

1
2
3
public interface Shape {
void draw();
}

Circle类

1
2
3
4
5
6
public class Circle implements Shape {
@Override
public void draw() {
System.out.println("draw a shape Circle...");
}
}

Rectangle类

1
2
3
4
5
6
public class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("draw a shape Rectangle...");
}
}

ShapeDecorator类,包含了对Shape的一个对象的引用

1
2
3
4
5
6
7
8
9
10
11
12
public abstract class ShapeDecorator implements Shape {
protected Shape decoratedShape;
public ShapeDecorator(Shape decoratedShape) {
this.decoratedShape = decoratedShape;
}
@Override
public void draw() {
decoratedShape.draw();
}
}

RedShapeDecorator类,实现了对原有的扩展

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class RedShapeDecorator extends ShapeDecorator {
public RedShapeDecorator(Shape decoratedShape) {
super(decoratedShape);
}
@Override
public void draw() {
decoratedShape.draw();
setBackgroundRed();
}
private void setBackgroundRed() {
System.out.println("Background Color : Red");
}
}

测试类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class DecoratorDemoTest {
@Test
public void decoratorDemoTest() {
Shape circle = new Circle();
Shape rectangle = new Rectangle();
Shape redCircle = new RedShapeDecorator(new Circle());
Shape redRectangle = new RedShapeDecorator(new Rectangle());
System.out.println("Circle with default color");
circle.draw();
System.out.print("\n");
System.out.println("Rectangle with default color");
rectangle.draw();
System.out.print("\n");
System.out.println("Circle with red color");
redCircle.draw();
System.out.print("\n");
System.out.println("Rectangle with red color");
redRectangle.draw();
System.out.print("\n");
}
}

总结

装饰模式与继承相比

  • 扩展面向的是对象
  • 不需要继承来实现扩展
  • 在运行的时候去分配职责
  • 具有更多的灵活性。

参考代码

------ 本文结束 ------

版权声明


BillyYccc's blog by Billy Yuan is licensed under a Creative Commons BY-NC-SA 4.0 International License.
本文原创于BillyYccc's Blog,转载请注明原作者及出处!