观察者模式(Observer)
定义对象间的一种一对多的依赖关系,使得每当一个状态发生改变时,其相关依赖对象皆得到通知并被自动更新。
在GoF23种设计模式中,属于行为型模式( Behavioral Patterns)
。
观察者模式又被称为发布订阅模式,由于高可用的要求,应用一般会以集群的模式部署。因此一般开发中都会使用分布式的发布订阅系统。如:zookeeper、kafka等。
如果你需要一个单机的发布订阅实现,jdk工具类已经帮你实现了该模式,而且线程安全。
- 优点
- 解耦观察者与被观察者
- 可广播通信
- 系统拓展性好
- 缺点
- 可能会循环调用导致系统崩溃
- 使用场景
- 消息发布订阅
实例
角色说明
- Subject
- 被观察对象抽象接口
- ConcreteSubject
- 具体的被观察对象
- Observer
- 观察者抽象接口
- ConcreteObserver
- 具体的观察者
- Client
- 使用者
举例
我们以点外卖为例。骑手是被观察者,订餐的人是观察者。
角色说明
- Observable(Subject)
- 被观察对象抽象接口
- Rider(ConcreteSubject)
- 骑手
- Observer(Observer)
- 观察者抽象接口
- Customer(ConcreteObserver)
- 顾客
- Client
- 外卖平台
code
- Rider.java
public class Rider extends Observable {
private String name;
public Rider(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void notifyCustomer(String message) {
setChanged();
notifyObservers(message);
System.out.println("亲爱的" + name + "骑士您好,订餐平台提醒您,消息已通知到顾客。");
}
}
- Customer.java
public class Customer implements Observer {
private String name;
public Customer(String name) {
this.name = name;
}
@Override
public void update(Observable o, Object arg) {
Rider rider = (Rider) o;
String message = (String) arg;
System.out.println("尊敬的" + name + "您好,骑手" + rider.getName() + "通知您," + message);
}
}
- Client.java
public class Client {
public static void main(String[] args) {
Rider rider = new Rider("张三");
Customer ordin = new Customer("ordin");
Customer willing = new Customer("willing");
System.out.println("群发消息:");
rider.addObserver(ordin);
rider.addObserver(willing);
rider.notifyCustomer("外卖正在路上,美味稍后就到!!!");
System.out.println("\n单独发给willing:");
rider.deleteObserver(ordin);
rider.notifyCustomer("外卖正在路上,美味稍后就到!!!");
}
}
- output
群发消息:
尊敬的willing您好,骑手张三通知您,外卖正在路上,美味稍后就到!!!
尊敬的ordin您好,骑手张三通知您,外卖正在路上,美味稍后就到!!!
亲爱的张三骑士您好,订餐平台提醒您,消息已通知到顾客。
单独发给willing:
尊敬的willing您好,骑手张三通知您,外卖正在路上,美味稍后就到!!!
亲爱的张三骑士您好,订餐平台提醒您,消息已通知到顾客。
注:Observabel与Observer均为jdk提供,这里就不贴源码了,放在下面实例解读中。
实例
code:java.util.Observer / java.util.Observable
- Observer.java
public interface Observer {
void update(Observable o, Object arg);
}
这里就是一个统一的订阅接口。我们具体看一下Observable的实现。
- Observable.java
public class Observable {
//发送开关
private boolean changed = false;
//Vector:线程安全的list
private Vector<Observer> 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);
}
public void notifyObservers() {
notifyObservers(null);
}
//通知所有观察对象, agr为通知内容
public void notifyObservers(Object arg) {
Object[] arrLocal;
synchronized (this) {
if (!changed)
return;
arrLocal = obs.toArray();
clearChanged();
}
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();
}
}
总结
观察者模式实现了观察与被观察者的解耦,主要用于消息的广播。
本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名,转载请标明出处
最后编辑时间为: