设计模式(12)——装饰器模式
本文介绍装饰器模式的概念和应用。
# 基本思想和原则
动态地给一个对象添加一些额外的职责。就增加功能来说,装饰器模式比生成子类更加灵活。
# 动机
我们经常有这样的需求,需要对一个对象进行扩展,一种能直接想到的方案是对原有类派生出多个子类,在子类中实现扩展的功能。这么做是可以,但是缺点也非常明显,继承是一种静态行为,如果我有很多特性需要动态添加到某个对象上,用继承的方式需要派生出非常多的子类,整个类体系臃肿不堪,类数量暴增,到最后根本无法维护。这时候使用装饰器模式可以有效避免这种灾难,装饰器是一种动态的行为,可以动态的增加一些功能到对象上,并且各个装饰器和原来的类耦合很小,扩展起来非常方便。
# 实现
public abstract class Handler {
public abstract void handle();
}
public class RequestHandler extends Handler {
@Override
public void handle() {
System.out.println("Request processing success.");
}
}
public abstract class Decorator extends Handler {
private Handler handler;
public Decorator(Handler handler) {
this.handler = handler;
}
@Override
public void handle() {
this.handler.handle();
}
}
public class LogDecorator extends Decorator {
public LogDecorator(Handler handler) {
super(handler);
}
private void log() {
System.out.println("LogDecorator log.");
}
public void handle() {
super.handle();
this.log();
}
}
public class BlacklistDecorator extends Decorator {
public BlacklistDecorator(Handler handler) {
super(handler);
}
private void filterBlacklist() {
System.out.println("BlacklistDecorator filter blacklist.");
}
public void handle() {
this.filterBlacklist();
super.handle();
}
}
public class Test {
public static void main(String[] args) {
Handler requestHandler = new RequestHandler();
System.out.println("------ Has no decorator ------");
requestHandler.handle();
System.out.println();
System.out.println("------ Add a log decorator ------");
requestHandler = new LogDecorator(requestHandler);
requestHandler.handle();
System.out.println();
System.out.println("------ Add a blacklist decorator ------");
requestHandler = new BlacklistDecorator(requestHandler);
requestHandler.handle();
}
}
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
63
64
65
66
67
68
69
70
71
72
73
输出如下:
------ Has no decorator ------
Request processing success.
------ Add a log decorator ------
Request processing success.
LogDecorator log.
------ Add a blacklist decorator ------
BlacklistDecorator filter blacklist.
Request processing success.
LogDecorator log.
2
3
4
5
6
7
8
9
10
11
上面的代码模拟了一个请求被处理的过程,其中RequestHandler
类负责实际地处理一个请求,此时我们想在这个基础上增加过滤黑名单和记录日志的功能。使用装饰器模式可以很容易地实现这个功能,装饰器抽象类Decorator
可以派生出很多具体的装饰器类,这些装饰器类在内部都维护一个Handler
类的实例,装饰器也需要实现Handler
类的handle
方法,在内部实际上是将具体的处理过程委托
给了this.handler
去处理,在具体的处理前后增加需要扩展的功能。
BlacklistDecorator
装饰器是在请求被处理前进行黑名单检查,LogDecorator
装饰器是在请求被处理后进行日志记录。可以看到当在原对象上增加一个装饰器,实际上就是对原对象进行了一层包装,增加几个装饰器就是包装几层。
实际上很多 Web Framework 中的过滤器都是采用装饰器的模式来实现的。
# 优点
装饰器和被装饰的对象相互之间可以独立扩展,耦合度比较低。装饰器模式可以实现对一个对象动态地扩展功能,非常灵活。装饰器模式是比生成子类更轻量级的扩展方式。
# 缺点
要注意对一个对象的装饰层数不要太多,否则调试起来会比较困难。