观察者模式
定义
在对象之间定义了一对多的依赖,这样一来,当一个对象(Subject)改变状态,依赖它的对象(Observer)会收到通知并自动更新。
角色
- 抽象被观察者角色:也就是一个抽象主题,它把所有对观察者对象的引用保存在一个集合中,每个主题都可以有任意数量的观察者。抽象主题提供一个接口,可以增加和删除观察者角色。一般用一个抽象类和接口来实现。
- 抽象观察者角色:为所有的具体观察者定义一个接口,在得到主题通知时更新自己。
- 具体被观察者角色:也就是一个具体的主题,在集体主题的内部状态改变时,所有登记过的观察者发出通知。
- 具体观察者角色:实现抽象观察者角色所需要的更新接口,一边使本身的状态与制图的状态相协调。
示例
抽象主题接口
public interface Subject {
public void registe(Observer o);
public void unregiste(Observer o);
public int size();
public void notifyObserver();
}
主题实现类A
public class SubjectA implements Subject {
private List<Observer> observers ;
public SubjectA() {
observers = new ArrayList<Observer>();
}
@Override
public void registe(Observer o) {
observers.add(o);
}
@Override
public void unregiste(Observer o) {
observers.remove(o);
}
@Override
public int size() {
return this.observers.size();
}
@Override
public void notifyObserver() {
for (Observer observer : observers) {
observer.update();
}
}
}
观察者(订阅者)接口
public interface Observer {
public void update();
public void unregist();
}
观察者实现类A
public class ObserverA implements Observer {
private Subject subject;
public ObserverA(Subject subject) {
this.subject = subject;
subject.registe(this);
}
@Override
public void update() {
System.out.println("ObserverA被通知");
}
@Override
public void unregist(){
subject.unregiste(this);
}
}
观察者实现类B
public class ObserverB implements Observer {
private Subject subject;
public ObserverB(Subject subject) {
this.subject = subject;
subject.registe(this);
}
@Override
public void update() {
System.out.println("ObserverB被通知");
}
@Override
public void unregist(){
subject.unregiste(this);
}
}
测试类
public class ObserverTest {
public static void main(String[] args) {
SubjectA subjectA = new SubjectA();
Observer observerA = new ObserverA(subjectA);
Observer observerB = new ObserverB(subjectA);
System.out.println("订阅者:"+subjectA.size());
subjectA.notifyObserver();
observerB.unregist();
System.out.println("=======observerB unregist========");
System.out.println("订阅者:"+subjectA.size());
subjectA.notifyObserver();
}
}
分析
- Observer订阅主题Subject,通过构造器将subject保存(方便下面取消注册等等),并使用subject的regist方法注册,subject改变时会调用notifyObserver方法,方法中遍历调用observer的update方法通知observer做出改变,需要取消注册时observer调用unregist取消注册;
- 这个模式是松偶合的。改变主题或观察者中的一方,另一方不会受到影像。
- JDK中也有自带的观察者模式。但是被观察者是一个类而不是接口,限制了它的复用能力。
- zookeeper就是利用的这种模式,服务端将服务暴露在某个节点上,客户端订阅某个节点的变化,当节点有变化时回调客户端的process方法处理;