观察模式

观察者模式(有时又被称为发布-订阅模式、模型-视图模式、源-收听者模式或从属者模式)是软件设计模式的一种。
在此种模式中,一个目标物件管理所有相依于它的观察者物件,并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。
此种模式通常被用来实作事件处理系统。
简单点概括成通俗的话来说,就是一个类管理着所有依赖于它的观察者类,并且它状态变化时会主动给这些依赖它的类发出通知。

观察者模式
观察者模式

我们的被观察者类Observable只关联了一个Observer的列表,然后在自己状态变化时,使用notifyObservers方法通知这些Observer,具体这些Observer都是什么,被观察者是不关心也不需要知道的。

一对多的方法,当一个对象的状态发生改变,那么依赖这个状态的相应对象都会发生改变。
目标与观察者的关系,可以多目标一个观察者,也可以多个观察者一个目标
单向依赖:只有目标什么更新观察者
命名:目标subject,观察者observer,更新方法update
触发通知的时机:先设置值再更新
观察者实现的顺序:
通知顺序:顺序不确定

推模型和拉模型

推模型:

目标对象主动向观察者推送目标的详细信息,推送的信息通常是目标对象的全部或者部分数据,广播方式,在update方法中传递的是定制的内容

拉模型:

目标对象在通知观察着的时候,只传递少量信息
如果观察者需要更具体的信息,有观察者主动到目标对象中去获取,相当于观察者从目标对象中拉数据
一般这种模型的实现中,会把目标对象自身通过update方法传递给观察者

比较:

推模型假定目标是知道自己想要什么的,因此update中传递的是定制的值,同时这样做会使得代码难以复用
拉模型是目标对象不知道自己想要什么值,因此要把对象本身给观察者,由观察者来取值

java中对观察者模式的实现

由于JDK中为了方便开发人员,已经写好了现成的观察者接口和被观察者类
观察者接口。

1
2
3
4
5
//观察者接口,每一个观察者都必须实现这个接口
public interface Observer {
//这个方法是观察者在观察对象产生变化时所做的响应动作,从中传入了观察的对象和一个预留参数
void update(Observable o, Object arg);
}

被观察者类

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
import java.util.Vector;
//被观察者类
public class Observable {
//这是一个改变标识,来标记该被观察者有没有改变
private boolean changed = false;
//持有一个观察者列表
private Vector obs;
public Observable() {
obs = new Vector();
}
//添加观察者,添加时会去重
public synchronized void addObserver(Observer o) {
if (o == null)
throw new NullPointerException();
if (!obs.contains(o)) {
obs.addElement(o);
}
}
//删除观察者
public synchronized void deleteObserver(Observer o) {
obs.removeElement(o);
}
//notifyObservers(Object arg)的重载方法
public void notifyObservers() {
notifyObservers(null);
}
//通知所有观察者,被观察者改变了,你可以执行你的update方法了。
public void notifyObservers(Object arg) {
//一个临时的数组,用于并发访问被观察者时,留住观察者列表的当前状态,这种处理方式其实也算是一种设计模式,即备忘录模式。
Object[] arrLocal;
//注意这个同步块,它表示在获取观察者列表时,该对象是被锁定的
//也就是说,在我获取到观察者列表之前,不允许其他线程改变观察者列表
synchronized (this) {
//如果没变化直接返回
if (!changed)
return;
//这里将当前的观察者列表放入临时数组
arrLocal = obs.toArray();
//将改变标识重新置回未改变
clearChanged();
}
//注意这个for循环没有在同步块,此时已经释放了被观察者的锁,其他线程可以改变观察者列表
//但是这并不影响我们当前进行的操作,因为我们已经将观察者列表复制到临时数组
//在通知时我们只通知数组中的观察者,当前删除和添加观察者,都不会影响我们通知的对象
for (int i = arrLocal.length-1; i>=0; i--)
((Observer)arrLocal[i]).update(this, arg);
}
//删除所有观察者
public synchronized void deleteObservers() {
obs.removeAllElements();
}
//标识被观察者被改变过了
protected synchronized void setChanged() {
changed = true;
}
//标识被观察者没改变
protected synchronized void clearChanged() {
changed = false;
}
//返回被观察者是否改变
public synchronized boolean hasChanged() {
return changed;
}
//返回观察者数量
public synchronized int countObservers() {
return obs.size();
}
}

点评

观察者和目标之间是松耦合;观察者实现了动态联动;观察者支持广播通信
可能会引起无谓的操作
何时使用观察者模式
http://www.runoob.com/design-pattern/observer-pattern.html
http://www.cnblogs.com/zuoxiaolong/p/pattern7.html
http://www.cnblogs.com/fingerboy/p/6393644.html
http://abc08010051.iteye.com/blog/1972960

回调函数

http://www.cnblogs.com/heshuchao/p/5376298.html
https://www.zhihu.com/question/19801131
http://blog.csdn.net/xiaanming/article/details/8703708

事件监听

https://my.oschina.net/u/923324/blog/792857

责任链模式

责任链模式是一种对象的行为模式。
在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。
发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求,这使得系统可以在不影响客户端的情况下动态地重新组织和分配责任。

实现

责任链模式
责任链模式

责任链模式涉及到的角色如下所示:
抽象处理者(Handler)角色:定义一个处理请求的抽象类。如果需要,可以定义一个方法以设定和返回对下家的引用。
具体处理者(ConcreteHandler)角色:具体处理者接到请求后,可以选择将请求处理掉,或者将请求传给下家。由于具体处理者持有对下家的引用,因此,如果需要,具体处理者可以访问下家。

纯的与不纯的责任链模式

一个纯的责任链模式要求一个具体的处理者对象只能在两个行为中选择一个:一是承担责任,而是把责任推给下家。不允许出现某一个具体处理者对象在承担了一部分责任后又把责任向下传的情况。
在一个纯的责任链模式里面,一个请求必须被某一个处理者对象所接收;在一个不纯的责任链模式里面,一个请求可以最终不被任何接收端对象所接收。
纯的责任链模式的实际例子很难找到,一般看到的例子均是不纯的责任链模式的实现。

点评

不用职责链的结构,我们需要和公司中的每一个层级都发生耦合关系。
如果反映在代码上即使我们需要在一个类中去写上很多丑陋的if….else语句。
如果用了职责链,相当于我们面对的是一个黑箱,我们只需要认识其中的一个部门,然后让黑箱内部去负责传递就好了

缺点:构造大量的对象,但是最终只有一个对象响应请求,因此内存中的性能会有所损耗,可以使用观察者模式代替
还有就是责任链必须遍历整条链才能找到响应,比较耗时

应用:异常处理,filter(多个filter可以响应,不止是一个)
http://www.cnblogs.com/java-my-life/archive/2012/05/28/2516865.html

http://blog.csdn.net/zuoxiaolong8810/article/category/1434962/2