设计模式(12)-装饰模式

思想:为一个对象已有的子类添加一些额外的职责。
场景:该模式的使用场景,主要是有的时候我们不愿意定义逻辑上新的子类,因为没有新的逻辑含义上的子类概念,而只是想为一个已存在的子类附加 一些职责。
实现:该 模式的实现主要就是定义一个物理上的新的子类,但是,它只是包含要附加职责的类,传递外部对相同接口的调用,在这个传递调用的通道上附加额外的功能。突然 想到,Decorator模式是不是一定程度上也能代替DynamicProxy模 式,从而成为一种AOP实现的方案呢?

重构成本:低。定义一个Decorator和一个已有类的逻辑上的子类,物理 表现形式上都是一个子类,重构也确实不是难事。

Decorator装饰设计模式是动态给一个对象添加一些额外的职责,但同时又不影响对象本身已有的功能。
通常使用继承来实现功能的扩展,但是如果这些需要扩展的功能的种类很烦多,就会生成很多子类,增加系统复杂性。同时由于使用继承实现功能的扩展时,必须可预见这些扩展功能,这些功能是编译时就确定的了,是静态的。使用Decorator装饰设计模式就可以根据功能需要有用户动态决定加入的方式和时机,实现“即插即用”的功能,在运行时动态决定增加何种功能。
Decorator装饰设计模式中的两种角色:
Decoratee被装饰者:即需要功能增强的原始对象,即目标对象。
Decorator装饰者:为原始对象提供功能增强的对象。
装饰者模式UML图如下:
这里写图片描述
Java swing中的JTextArea组件默认没有滚动条和边框,我们使用Decorator装饰设计模式动态为其加上滚动条和边框,使用Decorator装饰设计模式例子实现的例子代码如下:

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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62

interface VisualComponent{
public void draw();
}
//Decoratee
class TextArea implements VisualComponent {
public void draw(){
System.out.println(“Draw TextArea”);
}
}
//抽象Decorator
abstract class Decorator implements VisualComponent {
protected VisualComponent component;
public Decorator(VisualComponent component){
this.component = component;
}
public void draw(){
component.draw();
}
}
//滚动条Decorator
class ScrollDecorator extends Decorator{
public ScrollDecorator (VisualComponent component){
super(component);
}
public void draw(){
super.draw();
scrollTo();
}
public void scrollTo(){
System.out.println(“TextArea scroll to…”);
}
}
//边框Decorator
class BorderDecorator extends Decorator{
public BorderDecorator(VisualComponent component){
super(component);
}
public void draw(){
super.draw();
drawBorder();
}
public void drawBorder (){
System.out.println(“Draw border for TextArea …”);
}
}
public class DecoratorDemo{
public static void main(String[] args){
//画一个普通的TextArea
TextArea textArea = new TextArea();
textArea.draw();
//画一个带滚动条的TextArea
ScrollDecorator scroll = new ScrollDecorator(new TextArea());
scroll.draw();
//画一个带边框的TextArea
BorderDecorator border = new BorderDecorator(new TextArea());
border.draw();
//画一个既带边框又带滚动条的TextArea
BorderDecorator border2 = new BorderDecorator(new ScrollDecorator(new TextArea()));
border2.draw();
}
}

Decorator装饰设计模式和Proxy代理模式的区别:
Decorator装饰设计模式和Proxy代理模式非常类似,都可以对目标对象做一些动态改变,以致于很多初学者分不清楚Decorator装饰设计模式和Proxy代理模式,个人觉得二者简单区别如下:
(1).Proxy代理模式中,客户端不直接调用服务端程序,而是通过一个代理对象来调用服务端程序,类似一个请求转发的作用。
(2). Decorator装饰设计模式中,被装饰对象可以不用添加任何装饰而直接使用,也可以通过装饰器的包装动态增强功能。
JDK中装饰者模式的应用:
•java.io包
•java.util.Collections#synchronizedList(List)
•AWT和Swing图形组件