1、观察者模式介绍
观察者定义了一种一对多的依赖关系,当一个主题(Subject)对象状态发生变化时,所有依赖它的相关对象都会得到通知并且能够自动更新自己的状态,这些依赖的对象称之为观察者(Observer)对象这类似于发布/订阅模式。
观察者模式中的主题对象,会维持着一个依赖它的观察者对象列表,当主题对象状态发生改变时,主题对象便会调用这个列表中所有观察者对象的方法。
观察者模式一般用在分布式时间处理系统,它也是流行的MVC模型的核心设计模式。
在程序中,很多时候,我们需要等待另一方的一个状态来决定如何进行下一步,这个时候就需要不断的循环去查看对方的状态,不断轮询对CPU资源的占用是非常的大的,而且是空跑,做无用功。
观察者模式就是为了解决这样子的问题而产生的。他不是不断轮询对方状态,而是把自己作为观察者,注册到对方的对象中,这样,对方状态改变时,直接调用自己的触发方法(update)进行工作即可,从而较少了自己不断轮询带来的性能消耗。
其中比较经典的就是Java的swing,比如要等到button click事件发生,然后去做一件事情,只需要给这个button对象注册一个观察者(listener),当button对象的click发生时,调用listener的对应方法去处理相应逻辑。
以上的这种做法,只能够在单机版程序中,对象大家都在同一个jvm堆内存中,可以将引用交给对方,但是如果在分布式程序中,不同的组件运行在不同的机器集群。
2、代码示例
-
1、被订阅号
import java.util.Observable; /** * [@Author](https://my.oschina.net/arthor) liufu * @CreateTime 2018/3/28 17:37 */ public class ServiceProvider extends Observable { int offset = 0; private String data; public String getData() { return data; } public void setData(String data) { offset++; if (this.data != data){ System.out.println(data); this.data = data; //这两个必须组合使用,否则无效 //notifyObservers不要求传递参数,参数会传递给订阅者的update方法 setChanged(); notifyObservers(offset); } this.data = data; } }
-
2、观察者1
import java.util.Observable; import java.util.Observer; /** * [@Author](https://my.oschina.net/arthor) liufu * @CreateTime 2018/3/28 17:46 */ public class Observer1 implements Observer { /** * 创建对象的时候,订阅某个主题 * [@param](https://my.oschina.net/u/2303379) sp */ public Observer1(ServiceProvider sp){ sp.addObserver(this); } /** * 被订阅的对象发生变化了,这里要做相应的处理 * @param o * @param arg */ @Override public void update(Observable o, Object arg) { ServiceProvider provider = (ServiceProvider) o; System.out.println("Observer1: 我收到了,你想说的是:{" + provider.getData() + "}, offset: " + arg.toString()); } }
-
3、观察者2
import java.util.Observable; import java.util.Observer; /** * @Author liufu * @CreateTime 2018/3/28 17:46 */ public class Observer2 implements Observer { /** * 创建对象的时候,订阅某个主题 * @param sp */ public Observer2(ServiceProvider sp){ sp.addObserver(this); } /** * 被订阅的对象发生变化了,这里要做相应的处理 * @param o * @param arg */ @Override public void update(Observable o, Object arg) { //这里阻塞了,导致1和3都要等待,说明ServiceProvider回调的时候不是开线程处理 try { Thread.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); } ServiceProvider provider = (ServiceProvider) o; System.out.println("Observer2: 我收到了,你想说的是:{" + provider.getData() + "}, offset: " + arg.toString()); } }
-
4、观察者3
import java.util.Observable; import java.util.Observer; /** * @Author liufu * @CreateTime 2018/3/28 17:46 */ public class Observer3 implements Observer { /** * 创建对象的时候,订阅某个主题 * @param sp */ public Observer3(ServiceProvider sp){ sp.addObserver(this); } /** * 被订阅的对象发生变化了,这里要做相应的处理 * @param o * @param arg */ @Override public void update(Observable o, Object arg) { ServiceProvider provider = (ServiceProvider) o; System.out.println("Observer3: 我收到了,你想说的是:{" + provider.getData() + "}, offset: " + arg.toString()); } }
-
5、测试调度类
public class ObServerTest { public static void main(String[] args) { //先创建订阅号 ServiceProvider serviceProvider = new ServiceProvider(); //执行的顺序是2 --> 1 --> 3 Observer1 observer1 = new Observer1(serviceProvider); Observer2 observer2 = new Observer2(serviceProvider); Observer3 observer3 = new Observer3(serviceProvider); serviceProvider.setData("亲爱们,我变美了,你知道吗!"); serviceProvider.setData("亲爱们,我you变美了,你知道吗!"); } }