观察者模式
来源:互联网 发布:mac如何全选照片 编辑:程序博客网 时间:2024/06/06 14:14
@(设计模式)
观察者模式
我知道android的listview是用的观察者模式,Eventbus也是用的观察者模式。但是我还是不能灵活的使用这种设计模式。所以我想整理一下这种设计模式,以便加深对于这种设计模式的理解。
什么是观察者模式,观察者模式是用来做什么的?
每种设计模式都是用于解决软件开发中的一些通用问题产生的,观察者模式同样如此。
这里引入一下 (“Jva与模式“书中的话):
观察者模式是对象行为模式,又叫发布-订阅(publish/Subscribc模式)、模型与-视图(Model/View)模式。
观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象,这个主题对象在状态上发生变化时,会通知所有的观察者对象,使它们能够自动更新自己。
加粗的这句我觉得是观察者模式解决的软件开发问题,需要重点理解一下。 结合我所知道的设计的模式的使用可以这样理解,listview需要监听数据的变化,来更新item的显示, 而Eventbus需要根据用户发布的事件,来通知所有的订阅者来做出相应的处理。
所以在软件开发的过程中,遇到多个对象依赖一个对象的情况,就需要考虑引入观察者模式。
说了理解,下面整理一下用java代码实现观察模式, 在写代码之前呢,我们可以想象一下,如果要用java代码实现观察者模式要怎么设计呢。 首先整理一下功能需求,我们要实现的功能就是观察者模式的定义。
观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象,这个主题对象在状态上发生变化时,会通知所有的观察者对象,使它们能够自动更新自己。
简单点说,其实要实现的就是,当一个对象发生改变的时候,我们要通知和他相关联的对象也跟随着进行改变。那我们可以把发生改变的对象称为被观察者,跟随改变的对象称为观察者。 那其实可以想象的到, 被观察者对象类中应该有一个集合,里面是我们所有的观察者对象,当被观察者对象发生改变的时候,遍历集合中的所有的观察者然后通知他们进行同步的改变。 所以我们的观察者对象中应该有一个更新方法。 再回到被观察者对象,既然类中有个集合保存所有需要通知的观察者,那么是不是应该有一个添加观察者,移除观察者的方法呢。 还有就是如果要通过观察者进行改变,那是不是应该要有个标识呢。
好,总结一下,观察者和被观察者类中应该有的方法:
观察者: 同步进行更新的方法
被观察者: 观察者集合, 添加观察者的方法,移除观察者的方法,标识是否更新的方法,通知所有的观察者更新的方法。
那,既然所有的观察者,被观察者都应该有以上方法,那我们是不是应该把他们提取出来呢。 很机智啊,有没有!
其他JDK已经帮我们封装好了。在JAVA语言的java.util库里面,提供了一个Observable类以及一个Observer接口。其中Observable类就对应着我们的被观察者抽象类。Observer接口就对应着观察者抽象类。 方法和我们总结的很类似,就直接上代码了。
Observer接口:
这个接口只定义了一个方法,即update()方法,当被观察者对象的状态发生变化时,被观察者对象的notifyObservers()方法就会调用这一方法。
public interface Observer { void update(Observable o, Object arg);}
Observable类:
被观察者类都是java.util.Observable类的子类。java.util.Observable提供公开的方法支持观察者对象,这些方法中有两个对Observable的子类非常重要:一个是setChanged(),另一个是notifyObservers()。第一方法setChanged()被调用之后会设置一个内部标记变量,代表被观察者对象的状态发生了变化。第二个是notifyObservers(),这个方法被调用时,会调用所有登记过的观察者对象的update()方法,使这些观察者对象可以更新自己。
public class Observable { private boolean changed = false; private Vector obs; /** Construct an Observable with zero Observers. */ 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); } /** * 如果本对象有变化(那时hasChanged 方法会返回true) * 调用本方法通知所有登记的观察者,即调用它们的update()方法 * 传入this和arg作为参数 */ 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(); } /** * 将“已变化”设置为true */ protected synchronized void setChanged() { changed = true; } /** * 将“已变化”重置为false */ protected synchronized void clearChanged() { changed = false; } /** * 检测本对象是否已变化 */ public synchronized boolean hasChanged() { return changed; } /** * Returns the number of observers of this <tt>Observable</tt> object. * * @return the number of observers of this object. */ public synchronized int countObservers() { return obs.size(); }}
下面我们进入正题,要怎么基于目前的抽象类,实现观察者模式:
想向一个业务场景,日常开发的过程中,我们都会订阅一些技术网站,向开发者头条之类的。而每次他们发布新消息的时候我们就能同步的收到消息。就其实就类似一种观察者模式。 我们是观察者, 技术网站是被观察者。上代码理解一下:
/** * 程序员是观察者 * * @author mrsimple */public class Coder implements Observer { public String name ; public Coder(String aName) { name = aName ; } @Override public void update(Observable o, Object arg) { System.out.println( "Hi, " + name + ", 开发者头条更新啦, 内容 : " + arg); } @Override public String toString() { return "码农 : " + name; }}
可以看到Coder 是观察者,实现了Observer 接口。 然后等被观察者,同步更新状态的时候会调用update方法。
/** * AndroidWeekly这个网站是被观察者,它有更新所有的观察者 (这里是程序员) 都会接到相应的通知. * * @author mrsimple */public class DeveloperNews extends Observable { public void postNewPublication(String content) { // 标识状态或者内容发生改变 setChanged(); // 通知所有观察者 notifyObservers(content); }}
DeveloperNews 是被观察者对象,继承了Observable 类, 当每次发布新的新闻的时候,调用postNewPublication方法,而在postNewPublication中调用基类的setChanged,notifyObservers两个方法。去通知所有的观察者进行更新状态。
测试代码:
public static void main(String[] args) throws Exception { // 被观察的角色 DeveloperNews androidWeekly = new DeveloperNews(); // 观察者 Coder coder0 = new Coder("coder-0"); Coder coder1 = new Coder("coder-1"); Coder coder2 = new Coder("coder-2"); Coder coder3 = new Coder("coder-3"); // 将观察者注册到可观察对象的观察者列表中 androidWeekly.addObserver(coder0); androidWeekly.addObserver(coder1); androidWeekly.addObserver(coder2); androidWeekly.addObserver(coder3); // 发布消息 androidWeekly.postNewPublication("新的一期AndroidWeekly来啦!");}
输出:
Hi, coder-3, 开发者头条更新啦, 内容 : 新的一期AndroidWeekly来啦!Hi, coder-2, 开发者头条更新啦, 内容 : 新的一期AndroidWeekly来啦!Hi, coder-1, 开发者头条更新啦, 内容 : 新的一期AndroidWeekly来啦!Hi, coder-0, 开发者头条更新啦, 内容 : 新的一期AndroidWeekly来啦!
观察者模式的理解和使用目前我就总结了这些,以后应该会补充更多的使用心得。
- 观察者模式
- 观察者模式
- 观察者模式
- 观察者模式
- 观察者模式
- 观察者模式
- 观察者模式
- 观察者模式
- 观察者模式
- 观察者模式
- 观察者模式
- 观察者模式
- 观察者模式
- 观察者模式
- 观察者模式
- 观察者模式
- 观察者模式
- 观察者模式
- 1014. Waiting in Line (30)
- hive 自动生成动态分区
- Tp中的多层控制器和多级控制器使用
- makefile 可以自动推导生成.o规则
- ACM书中的题目 j-10
- 观察者模式
- 前端练习小记
- 我眼中的光明·第七周·注意力·二
- Drools规则引擎在支付结算对账中的应用
- Codeforces #404 (Div. 2) B. Anton and Classes (贪心
- 网页返回更新
- 提高代码质量的技巧
- std::vector : 用法与技巧
- unity 文件 路径 笔记