OBSERVER(观察者)
1、 意图
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
2、 别名
依赖(Dependents),发布-订阅(Publish-Subscribe)
3、 适用性
- 当一个抽象模型有两个方面,其中一个方面依赖于另一个方面。将这二者封装在独立的对象中以使它们可以各自独立地改变和复用。
- 当对一个对象的改变需要同时改变其他对象,而不知道具体有多少对象有待改变。
- 当一个对象必须通知其他的对象,而它又不能假定其他对象是谁。也就是说,你不希望这些对象是紧密耦合的。
4、 结构
5、 参与者
Subject
——目标知道它的观察者。可以有任意多个观察者观察同一个目标。
——提供注册和删除观察者对象的接口。
Observer
——为那些在目标发生改变时需获得通知的对象定义一个更新接口。
ConcreteSubject
——将有关状态存入各ConcreteObserver对象。
——当它的状态发生改变时,向它的各个观察者发出通知。
ConcreteObserver
——维护一个指向ConcreteSubject对象的引用。
——存储有关状态,这些状态应与目标的状态保持一致。
——实现Observer的更新接口以使自身状态和目标的状态保持一致。
6、 协作
- 当ConcreteSubject发生任何可能导致其观察者与其本身状态不一致的改变时,它将通知它的各个观察者。
- 在得到一个具体目标的改变通知后,ConcreteObserver对象可向目标对象查询信息。ConcreteObserver使用这些信息以使它的状态与目标对象的状态一致。
7、 效果
Observer模式允许你独立地改变目标和观察者。你可以单独复用目标对象而无需同时复用其观察者,反之亦然。它也使你可以在不改变目标和其他的观察者的前提下增加观察者。
1) 目标和观察者间的抽象耦合。一个目标所知道的仅仅是它有一系列观察者,每个都符合抽象的Observer类的简单接口。目标不知道任何一个观察者属于哪一个具体的类。这样目标和观察者之间的耦合是抽象和最小的。
2) 支持广播通信。不像通常的请求,目标发送的通知不需指定它的接收者。通知被自动广播给所有已向该目标对象登记的有关对象。目标对象并不关心到底有多少对象对自己感兴趣;它唯一的责任就是通知它的各观察者。
3) 意外的更新因为一个观察者并不知道其他观察者的存在,它可能改变目标的最终代价一无所知。在目标上看似无害的操作可能会引起一系列对观察者以及依赖于这些观察者的那些对象的更新。
8、 代码示例
Subject
package com.examples.pattern.observer;
import java.util.ArrayList;
import java.util.List;
/**
* 目标对象,它知道它的观察者,并提供注册和删除观察者的接口。
*/
public class Subject {
/**
* 用来保存注册的观察者对象
*/
private List<Observer> observers = new ArrayList<Observer>();
/**
* 注册观察者对象
* @param observer 观察者对象
*/
public void attach(Observer observer){
observers.add(observer);
}
/**
* 删除观察者对象
* @param observer 观察者对象
*/
public void detach(Observer observer){
observers.remove(observer);
}
protected void notifyObservers(){
for(Observer observer : observers){
observer.update(this);
}
}
}
ConcreteSubject
package com.examples.pattern.observer;
/**
* 具体的目标对象,负责把有关状态存入到相应的观察者对象,
* 并在自己状态改变时,通知各个观察者。
*/
public class ConcreteSubject extends Subject {
/**
* 目标对象的状态
*/
private String subjectState;
public String getSubjectState() {
return subjectState;
}
public void setSubjectState(String subjectState) {
this.subjectState = subjectState;
//状态发生了改变,通知各个观察者
this.notifyObservers();
}
}
Observer
package com.examples.pattern.observer;
/**
* 观察者接口,定义一个更新的接口给那些目标发生改变的时候被通知的对象
*/
public interface Observer {
/**
* 更新的接口
*
* @param subject
* 传入目标对象,方便获取相应的目标对象的状态
*/
public void update(Subject subject);
}
ConcreteObserver
package com.examples.pattern.observer;
/**
* 具体观察者对象,实现更新的方法,使自身的状态和目标的状态保持一致
*/
public class ConcreteObserver implements Observer {
/**
* 观察者的状态
*/
private String observerState;
@Override
public void update(Subject subject) {
//具体的更新实现
//这里可能需要更新观察者的状态,使其与目标的状态保持一致
observerState = ((ConcreteSubject)subject).getSubjectState();
System.out.println(observerState);
}
}
Client
package com.examples.pattern.observer;
public class Client {
public static void main(String[] args) {
ConcreteSubject cs = new ConcreteSubject();
ConcreteObserver co_1 = new ConcreteObserver();
ConcreteObserver co_2 = new ConcreteObserver();
cs.attach(co_1);
cs.attach(co_2);
cs.setSubjectState("这里是观察者模式");
}
}
9、 相关模式
1)观察者模式与状态模式
观察者模式和状态模式是可以结合使用的。观察者模式的重心在触发联动,但是到底决定哪些观察者被联动,这时就可以采用状态模式来实现,也可以采用策略模式来进行选择需要联动的观察者。
2)观察者模式和中介模式