设计模式之——观察者设计模式
来源:互联网 发布:如何评价secrets 知乎 编辑:程序博客网 时间:2024/06/06 09:23
目前很火的RxJava其核心就是观察者模式,定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
举个现实中的例子方便大家理解:《每天一杯鲜牛奶》
小区中的住户订奶,他们和奶场签下协议,每天清晨,送奶员就会准时将新鲜的牛奶放在小区的奶箱中。那么,我们这些住户就相当于订阅者(观察者),奶场就是发布者(被观察者),到一定的时间,奶场通知送奶员发货,然后各家各户就自动收到了新鲜的奶了。其实这个协议就是内部的更新接口,奶场只是调用了通知送奶员的方法,然后传参(一杯鲜奶),调用住户的更新接口(奶箱)。
在比如:《作业风云》
老师布置作业,然后全班同学都知道了,老师就是被观察者,学生就是观察者,学生观察老师布置作业的动作,然后自个获取到这个状态就知道布置作业了。
好了,我们来看一下实现:
首先,我们先抽取这个通知的方法,也就是各个观察者实现的方法,具体的通知结果由各个实现者自个处理:
package com.zndroid.dm.ObserverModel.Custom;/** * Created by luzhenyu on 2017/9/11. *//**首先呢,我们抽象出观察者(订阅者),观察者起到更新通知的作用*/public interface Observer { void update(Object obj);}
我们搞几个观察者:
package com.zndroid.dm.ObserverModel.Custom.impl;import com.zndroid.dm.ObserverModel.Custom.Observer;import com.zndroid.dm.ObserverModel.Custom.Subject;/** * Created by luzhenyu on 2017/9/11. *//**具体实现三个观察者 - 1*/public class Observer1 implements Observer { @Override public void update(Object obj) { System.out.println("Observer1 found " + ((Subject)obj).getName() + " has changed!"); }}
package com.zndroid.dm.ObserverModel.Custom.impl;import com.zndroid.dm.ObserverModel.Custom.Observer;import com.zndroid.dm.ObserverModel.Custom.Subject;/** * Created by luzhenyu on 2017/9/11. *//**具体实现三个观察者 - 2*/public class Observer2 implements Observer { @Override public void update(Object obj) { System.out.println("Observer2 found " + ((Subject)obj).getName() + " has changed!"); }}
package com.zndroid.dm.ObserverModel.Custom.impl;import com.zndroid.dm.ObserverModel.Custom.Observer;import com.zndroid.dm.ObserverModel.Custom.Subject;/** * Created by luzhenyu on 2017/9/11. *//**具体实现三个观察者 - 3*/public class Observer3 implements Observer { @Override public void update(Object obj) { System.out.println("Observer3 found " + ((Subject)obj).getName() + " has changed!"); }}
下面呢,被观察者的行为有:add观察者,delete观察者,notify观察者;这些都是通用的,我们可以抽象出接口
package com.zndroid.dm.ObserverModel.Custom;/** * Created by luzhenyu on 2017/9/11. *//**定义被观察者公用接口*/public interface IObservable { void add(Observer observer); void delete(Observer observer); void notifications();}
下面是被观察者实现,其核心就是内部存储观察者列表,然后提供给外部(客户端)通知变化的方法,具体的变化会通知到观察者列表中每一个观察者具体的更新方法:
package com.zndroid.dm.ObserverModel.Custom;/** * Created by luzhenyu on 2017/9/11. */import java.util.ArrayList;import java.util.List;/**被观察者(发布者)*/public class Subject implements IObservable { private List<Observer> list;//订阅者列表 private String name; public Subject() { list = new ArrayList<>(); } @Override public void add(Observer observer) { System.out.println("Add a observer " + observer.toString()); list.add(observer);//添加订阅者 } @Override public void delete(Observer observer) { System.out.println("Delete a observer " + observer.toString()); list.remove(observer); } @Override public void notifications() { for (Observer o : list) { try { o.update(this); } catch (Exception e) { System.out.println("Error"); }//此部分也是JDK中欠考虑的部分 } } //通知订阅者发生变化的方法 public void changed() { System.out.println("Notify observers I'm changed "); notifications();//通知所有的订阅者‘我’发生变化了 } public String getName() { return name; } public void setName(String name) { this.name = name; }}
下面看一下使用:
/** * 观察者模式 * 定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。 * 其核心就是在抽象的被观察者类中存放观察者们。 * * 但是如果观察者非常多的话相应的时间也会很长;如果观察者与被观察者有循环依赖的话有可能会造成系统崩溃; * 观察者并不知道被观察者具体怎么变化的,他们只是知道变化了;如果使用的是Java自带的API,如果其中一个观察者出现更新异常就会影响剩下的观察者。 * * 现在很火的RxJava、RxAndroid核心就是观察者模式 * 在Java中被观察者继承java.util.Observable,观察者实现java.util.Observer接口就实现了观察者模式。 * */ ////////// 以下是手动实现 ////////// //实例化一个被观察者 Subject subject = new Subject(); subject.setName("我是一个小小的被观察者,好害羞啊"); Observer1 observer1 = new Observer1(); Observer2 observer2 = new Observer2(); Observer3 observer3 = new Observer3(); //添加订阅者 subject.add(observer1); subject.add(observer2); subject.add(observer3); //我要变化咯~~ subject.changed();//所有的订阅者都会收到通知 log("--------------------- Im delete a observer --------------------"); //去掉一个订阅者 subject.delete(observer2); subject.changed();//所有的订阅者都会收到通知 log("----------------我是分割线-----------------");
运行结果:
[ ======================================== ]
Add a observer com.zndroid.dm.ObserverModel.Custom.impl.Observer1@42a57993
Add a observer com.zndroid.dm.ObserverModel.Custom.impl.Observer2@75b84c92
Add a observer com.zndroid.dm.ObserverModel.Custom.impl.Observer3@6bc7c054
Notify observers I'm changed
Observer1 found 我是一个小小的被观察者,好害羞啊 has changed!
Observer2 found 我是一个小小的被观察者,好害羞啊 has changed!
Observer3 found 我是一个小小的被观察者,好害羞啊 has changed!
[ --------------------- Im delete a observer -------------------- ]
Delete a observer com.zndroid.dm.ObserverModel.Custom.impl.Observer2@75b84c92
Notify observers I'm changed
Observer1 found 我是一个小小的被观察者,好害羞啊 has changed!
Observer3 found 我是一个小小的被观察者,好害羞啊 has changed!
[ ----------------我是分割线----------------- ]
[ ======================================== ]
以上是我们手动实现的,在java中JDK已经有相应的实现了,我们来看一下怎么使用:
在Java中被观察者继承java.util.Observable,观察者实现java.util.Observer接口
比较源码会发现,和我们的思想是一致的:
//// Source code recreated from a .class file by IntelliJ IDEA// (powered by Fernflower decompiler)//package java.util;import java.util.Observable;//观察者接口,每个观察者都必须实现的接口,该接口是在被观察的对象发生变化时做出的相应public interface Observer { void update(Observable var1, Object var2);}
import java.util.Vector;//被观察者类public class Observable { //这是一个改变标识,来标记该被观察者有没有改变 private boolean changed = false; //持有一个观察者列表 private Vector 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); } //notifyObservers(Object arg)的重载方法 public void notifyObservers() { notifyObservers(null); } //通知所有观察者,被观察者改变了,你可以执行你的update方法了。 public void notifyObservers(Object arg) { //一个临时的数组,用于并发访问被观察者时,留住观察者列表的当前状态,这种处理方式其实也算是一种设计模式,即备忘录模式。 Object[] arrLocal; //注意这个同步块,它表示在获取观察者列表时,该对象是被锁定的 //也就是说,在我获取到观察者列表之前,不允许其他线程改变观察者列表 synchronized (this) { //如果没变化直接返回 if (!changed) return; //这里将当前的观察者列表放入临时数组 arrLocal = obs.toArray(); //将改变标识重新置回未改变 clearChanged(); } //注意这个for循环没有在同步块,此时已经释放了被观察者的锁,其他线程可以改变观察者列表 //但是这并不影响我们当前进行的操作,因为我们已经将观察者列表复制到临时数组 //在通知时我们只通知数组中的观察者,当前删除和添加观察者,都不会影响我们通知的对象 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(); }}
我们尝试使用一下:
package com.zndroid.dm.ObserverModel.Java;import java.util.Observable;/** * Created by luzhenyu on 2017/9/11. */public class TimerOb extends Observable { private long time; public long getTime() { return time; } public void setTime(long time) { this.time = time; } public void disPlay() { setChanged();//Java中必须要先告知状态已改变 notifyObservers(); }}
package com.zndroid.dm.ObserverModel.Java;import java.util.Observable;import java.util.Observer;/** * Created by luzhenyu on 2017/9/11. */public class Listener1 implements Observer { @Override public void update(Observable observable, Object o) { System.out.println(((TimerOb)observable).getTime()); }}
package com.zndroid.dm.ObserverModel.Java;import java.util.Observable;import java.util.Observer;/** * Created by luzhenyu on 2017/9/11. */public class Listener2 implements Observer { @Override public void update(Observable observable, Object o) { System.out.println(((TimerOb)observable).getTime()); }}
package com.zndroid.dm.ObserverModel.Java;import java.util.Observable;import java.util.Observer;/** * Created by luzhenyu on 2017/9/11. */public class Listener3 implements Observer { @Override public void update(Observable observable, Object o) { System.out.println(((TimerOb)observable).getTime()); }}
使用如下:
////////// 下面来看一下Java中自带的实现 ////////// TimerOb timerOb = new TimerOb(); Listener1 listener1 = new Listener1(); Listener2 listener2 = new Listener2(); Listener3 listener3 = new Listener3(); timerOb.addObserver(listener1); timerOb.addObserver(listener2); timerOb.addObserver(listener3); for (int i=0;i<4;i++) { try { Thread.sleep(1000); timerOb.setTime(System.currentTimeMillis()); timerOb.disPlay(); } catch (InterruptedException e) { e.printStackTrace(); } log("_________________"); } log("----------------我是分割线-----------------");
控制台输出,每隔一秒三个订阅者刷新当前时间:
[ ======================================== ]
1505114397015
1505114397015
1505114397015
[ _________________ ]
1505114398015
1505114398015
1505114398015
[ _________________ ]
1505114399015
1505114399015
1505114399015
[ _________________ ]
1505114400015
1505114400015
1505114400015
[ _________________ ]
[ ----------------我是分割线----------------- ]
[ ======================================== ]
【欢迎上码】
【微信公众号搜索 h2o2s2】
- 设计模式之——观察者模式
- 设计模式之——观察者模式
- 设计模式之——观察者模式
- 设计模式之——观察者模式
- 设计模式之——观察者模式
- 设计模式之 — Observer 观察者模式
- 设计模式学习之—观察者模式
- 设计模式—观察者
- 设计模式—观察者模式
- 设计模式—观察者模式
- 设计模式—观察者模式
- 设计模式—观察者模式
- 设计模式—观察者模式
- 设计模式—观察者模式
- 设计模式—观察者模式
- 设计模式—观察者模式
- 设计模式—观察者模式
- 设计模式之——观察者设计模式
- 112. Path Sum
- arcgis for js 船舶 拉旗
- 我们是如何做数据库运维和优化
- 想要购买二手域名先进行的四项检查
- Python笔记——类定义
- 设计模式之——观察者设计模式
- c语言_s错误解决
- spring管理属性配置文件properties——使用PropertiesFactoryBean
- HDOJ1425 sort(最简单的hash)
- 算法笔记:动态规划(DP)初步
- LintCode 恢复IP地址
- 文章标题
- 字符串转mac地址
- JS中的正则表达式