什么是观察者模式?
定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,他的所有依赖都会收到通知并能够自动更新。
其中,被依赖的对象称为主题(Subject),依赖的对象称为观察者(Observer)。简单点说:Subject 中维护了一个 Observer 的列表,每当有 Observer 订阅,就会被添加到这个列表,有 Observer 取消订阅,这个 Observer 就会被删除。当 Subject 状态发生改变时,就会遍历 Observer 列表,进行通知。订阅、取消订阅的时机以及触发改变的条件,根据业务逻辑而定。通知时,Observer 是用拉还是由 Subject 推,也根据实际需求定。
动手实现:
//Subject 接口
public interface Subject {
void addObserver(Observer observer);
void deleteObserver(Observer observer);
void notifyObservers();
void notifyObservers(Object data);
}
//Subject 实现
public class Publisher implements Subject {
private List<Observer> observers = new ArrayList<>();
private String msg;
private String status;
@Override
public void addObserver(Observer observer) {
observers.add(observer);
}
@Override
public void deleteObserver(Observer observer) {
if(observers.contains(observer)){
observers.remove(observer);
}
}
/**
* 拉数据
*/
@Override
public void notifyObservers() {
notifyObservers(null);
}
/**
* 推数据
* @param data
*/
@Override
public void notifyObservers(Object data) {
observers.forEach(observer -> observer.updateData(this, data));
}
public String getMsg() {
return msg;
}
/**
* 模拟状态变化, 拉数据
* @param msg
*/
public void setMsg(String msg) {
this.msg = msg;
notifyObservers();
}
public String getStatus() {
return status;
}
/**
* 模拟状态变化,推数据
* @param status
*/
public void setStatus(String status) {
this.status = status;
notifyObservers(status);
}
}
//Observer接口
public interface Observer {
void updateData(Subject subject,Object data);
}
//Observer实现
public class Subscriber1 implements Observer {
@Override
public void updateData(Subject subject, Object data) {
if(StringUtils.isEmpty(data)){
if(subject instanceof Publisher){
Publisher publisher = (Publisher)subject;
System.out.println("观察者1 收到信息(拉):" + publisher.getMsg() + "---" + publisher.getStatus());
}
}else{
System.out.println("观察者1 收到信息(推):" + data);
}
}
}
//测试类
@Test
void contextLoads() {
Publisher publisher = new Publisher();
Subscriber1 subscriber1 = new Subscriber1();
Subscriber2 subscriber2 = new Subscriber2();
publisher.addObserver(subscriber1);
publisher.addObserver(subscriber2);
publisher.setMsg("123");
publisher.setStatus("发送");
}
运行测试类的结果:
观察者1 收到信息(拉):123---null
观察者2 收到信息(拉):123---null
观察者1 收到信息(推):发送
观察者2 收到信息(推):发送
JDK 实现
这种模式 JDK 已经分装好了,分别是Observable类、Observer接口,原理和上面类似,但是多了一个 changed 属性,可以控制通知观察者的条件,例如:人数统计,每满100人次通知一次,避免通知过于频繁。
public void notifyObservers(Object arg) {
/*
* a temporary array buffer, used as a snapshot of the state of
* current Observers.
*/
Object[] arrLocal;
synchronized (this) {
/* We don't want the Observer doing callbacks into
* arbitrary code while holding its own Monitor.
* The code where we extract each Observable from
* the Vector and store the state of the Observer
* needs synchronization, but notifying observers
* does not (should not). The worst result of any
* potential race-condition here is that:
* 1) a newly-added Observer will miss a
* notification in progress
* 2) a recently unregistered Observer will be
* wrongly notified when it doesn't care
*/
if (!changed)
return;
arrLocal = obs.toArray();
clearChanged();
}
for (int i = arrLocal.length-1; i>=0; i--)
((Observer)arrLocal[i]).update(this, arg);
}
总结
- 订阅者与被订阅者松耦合
- 一旦被订阅者发生改变,订阅者能立马收到通知
典型应用
Websockt
JBotton事件监听
网友评论