前言
这几个概念其实都是设计模式你的概念, 其命名都跟真实场景密切相关, 理解了命名, 就了解了模式.
Filter
当你有一堆东西的时候,你只希望选择符合某些要求的东西。定义这些要求的工具,就是过滤器。
应用场景:
- 过滤掉非法url请求(不是login.do的地址请求,如果用户没有登陆都过滤掉),
- 在传入servlet或者 struts的action前统一设置字符集,
- 去除掉一些非法字符(聊天室经常用到的,一些骂人的话)。。。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| public class Test {
public static void main(String[] args) {
filter();
}
public static void filter() {
// 填充100个带有随机字母标签的球
List<String> array = new ArrayList<>();
Random r = new Random();
String[] balls = new String[]{"A", "B", "C"};
for (int i = 0; i < 100; i++) {
array.add(balls[r.nextInt(3)]);
}
System.out.println(array);
// 只拿出B的来。不明白的自行学习Java 8
array = array.stream().filter("B"::equals).collect(Collectors.toList());
System.out.println(array);
}
|
Interceptor
在一个流程正在进行的时候,你希望干预它的进展,甚至终止它进行,这是拦截器做的事情。
应用场景:
进行权限验证,或者是来判断用户是否登陆,日志记录,或者限制时间点访问。
我自己用过拦截器,是用户每次登录时,都能记录一个登录时间。 (这点用拦截器明显合适,用过滤器明显不合适,因为没有过滤任何东西)
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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
| interface Interceptor {
void intercept(River river);
}
public class Test {
public static void main(String[] args) {
RiverController rc = new RiverController();
Interceptor inter = new SomeInterceptor();
// 这一步通常叫做控制反转或依赖注入,其实也没啥子
rc.setInterceptor(inter);
rc.flow(new River());
}
}
class River {
// 流量
int volume;
// 总鱼数
int numFish;
@Override
public String toString() {
return "River{" +
"volume=" + volume +
", numFish=" + numFish +
'}';
}
}
class PowerGenerator {
double generate(int volume) {
// 假设每一百立方米水发一度电
return volume / 100d;
}
}
class SomeInterceptor implements Interceptor {
PowerGenerator generator = new PowerGenerator();
@Override
public void intercept(River river) {
// 消耗了1000立方米水来发电
int waterUsed = 1000;
// 水量减少了1000。
river.volume -= waterUsed;
// 发电
generator.generate(waterUsed);
// 拦截所有的鱼
river.numFish = 0;
System.out.println("passed interceptor");
}
}
class RiverController {
Interceptor interceptor;
void setInterceptor(Interceptor interceptor) {
this.interceptor = interceptor;
}
void flow(River river) {
// 大坝前, 源头积累下来的水量和鱼
river.volume += 100000;
river.numFish += 1000;
System.out.println(river);
// 经过了大坝
interceptor.intercept(river);
System.out.println(river);
// 下了点雨
river.volume += 1000;
}
}
|
Listener
当一个事件发生的时候,你希望获得这个事件发生的详细信息,而并不想干预这个事件本身的进程,这就要用到监听器。
应用场景:
当你要触发一个事件,但这件事既不是过滤,又不是拦截,那很可能就是监听! 联想到Windows编程里的,单击鼠标、改变窗口尺寸、按下键盘上的一个键都会使Windows发送一个消息给应用程序。监听器的概念类似于这些。
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
| // 监听器
interface BedListener {
// 监听器在参数中收到了某个事件,而这个事件往往是只读的
// 监听器的方法名通常以"on"开头
void onBedSound(String sound);
}
public class Test {
public static void main(String args[]) {
Neighbor n = new Neighbor();
n.setListener(sound -> generatePower());
n.doInterestingStuff();
}
private static void generatePower() {
// 根据当地法律法规,部分内容无法显示
}
}
// 邻居
class Neighbor {
BedListener listener;
// 依然是所谓控制反转
void setListener(BedListener listener) {
this.listener = listener;
}
void doInterestingStuff() {
// 根据当地法律法规,部分内容无法显示
// 将事件发送给监听器
listener.onBedSound("嘿咻");
listener.onBedSound("oyeah");
}
}
|
Summary
约定:
- 过滤器:用于属性甄别,对象收集(不可改变过滤对象的属性和行为)
- 监听器:用于对象监听,行为记录(不可改变监听对象的属性和行为)
- 拦截器:用于对象拦截,行为干预(可以改变拦截对象的属性和行为)
能力逐渐增强:过滤器–>监听器–>拦截器
三者的用法完全不同,不存在什么交集。你也可以用拦截器做过滤器的工作,但是大材小用了,也不符合约定。
References