公号:码农充电站pro
主页:https://codeshellme.github.iohtml
观察者模式(Observer Design Pattern)也被称为发布订阅模式(Publish-Subscribe Design Pattern),主要用于更好的解决向对象通知消息的问题。java
观察者模式定义了对象之间的一对多依赖,当对象状态改变的时候,全部依赖者都会自动收到通知。git
观察者模式能够用不少称呼来描述,好比:github
咱们以订阅报纸为例,来描述 Subject 与 Observer 之间的关系。redis
Subject 至关于报社,Observer 就至关于订阅报纸的用户:算法
Subject 与 Observer 是一对多关系:shell
这里直接给出观察者模式的类图,这是最经典的实现方式,其它的变种均可以在它的基础上加以改进。apache
从类图中能够知道,Subject 是一个接口,有三个抽象方法:设计模式
registerObserver
:用于注册 observer。removeObserver
:用于移除 observer。notifyObservers
:当有了消息,通知全部 observers。Observer 也是一个接口,有一个抽象方法:框架
update
:当 subject 发来新消息时,用于更新消息。下面咱们来用代码实现观察者模式。
首先是两个接口 Subject 与 Observer:
interface Subject { void registerObserver(Observer o); void removeObserver(Observer o); void notifyObservers(String info); } interface Observer { void update(String info); }
这两个接口彻底是按照类图中的内容来实现的,其中变量 info
的类型能够根据实际的应用场景来定。
再实现 ConcreteSubject 和 ConcreteObserver :
class ConcreteSubject implements Subject { // 用于存放 observer private final ArrayList<Observer> observers; public ConcreteSubject() { observers = new ArrayList(); } public void registerObserver(Observer o) { observers.add(o); } public void removeObserver(Observer o) { observers.remove(o); } public void notifyObservers(String info) { for (Observer o: observers) { o.update(info); } } } class ConcreteObserver implements Observer { private final String name; public ConcreteObserver(String name) { this.name = name; } public void update(String info) { System.out.println(this.name + " get info: " + info); } }
ConcreteSubject
中的 observers
用于存储观察者,这里使用的类型是 ArrayList
,也能够根据实际的应用场景来选择。
ConcreteObserver
中的 name
只是为了表示不一样的观察者,观察者在收到消息后,将消息打印在控制台。
测试这两个类:
// 建立被观察者 ConcreteSubject s = new ConcreteSubject(); // 建立两个观察者 ConcreteObserver o1 = new ConcreteObserver("o1"); ConcreteObserver o2 = new ConcreteObserver("o2"); // 注册观察者 s.registerObserver(o1); // 注册 o1 s.registerObserver(o2); // 注册 o2 s.notifyObservers("info1"); // 向观察者通知消息 System.out.println("remove observer o1"); s.removeObserver(o1); // 移除 o1 s.notifyObservers("info2"); // 再向观察者通知消息
输出以下:
o1 get info: info1 o2 get info: info1 remove observer o1 o2 get info: info2
能够看到,第一次通知消息时,o1 和 o2 都收到消息了,在移除 o1 以后再发送消息,只有 o2 能收到消息。
这就是观察者模式最简洁的一种实现方式,很是简单。我把完整的代码放在了这里。
根据不一样的应用场景和需求,观察者模式能够有不一样的实现方式,好比下面几种:
同步阻塞方式
根据这种划分方式,上面咱们实现的就是同步阻塞的方式,当有新消息的时候,Subject
会将消息 notify
给全部的 Observer
,直到全部的 Observer
执行完毕它的 update
过程,整个通知过程才算完毕,这整个过程是一个阻塞的过程。
异步非阻塞方式
为了加快整个 notify
过程,咱们能够将同步阻塞的方式改成异步非阻塞的方式。
一种简单的实现就是使用线程,就是在 update
方法中使用线程来完成任务,以下:
public void update(String info) { Thread t = new Thread(new Runnable() { public void run() { // 处理任务 } }); t.start(); }
Google Guava EventBusExplained 是一个通用的观察者模式框架,你能够去了解一下。
跨进程方式
同步阻塞与异步非阻塞都属于进程以内的实现,对于跨进程的实现,通常都是基于消息队列来实现。至于这方面的应用,有不少现成的,成熟的组件可使用,好比:
观察者模式旨在将观察者与被观察者解耦,在不少地方都用到了该模式,好比 Swing,JavaBeans 等。
观察者模式最经典的实现方式很简单,在实际应用中,能够在其基础上进行改进。
(本节完。)
推荐阅读:
欢迎关注做者公众号,获取更多技术干货。