设计模式——观察者模式
来源:互联网 发布:怎么安装mac os x 编辑:程序博客网 时间:2024/06/11 09:13
观察者模式又叫发布订阅模式,定义了对象间一对多的依赖关系。当一个对象发生变化,其他依赖此对象的对象们都会被通知,然后随之产生变化。举个栗子,当我们关注了某个人的博客(相当于订阅),当此博客有更新(发布了新文章),那么关注此博客的用户都会收到类似“您关注的博客有更新”这样的消息。诸如此类的模式就是观察者。
1. 观察者模式组成:
- 抽象主题:主题中包含了观察者的集合。并提供添加,删除以及通知观察者的接口。
- 具体主题对象:继承至抽象主题,用一个Vector存储观察者,内部维护了一个状态量,当状态发生改变,就向观察者进行通知。
- 抽象观察者:内部有update方法。这是为主题发生改变时需要获得通知的对象所建立的一个更新接口
- 具体观察者对象:实现了抽象观察者的接口。
按照惯例上一个观察者模式的类关系图:
Subject类方法介绍:
- observers:用一个Vector来存储observer
- add:添加观察者,即加入到Vector中
- delete:删除观察者
- notifyObservers:当Subject发生状态变化时,调用此方法通知所有的observer,即遍历Vector。至于怎么通知,在此方法中调用observer的update方法即可。
Observer类方法介绍:
-update:更新观察者的状态,使其与subject状态一致
2. 照惯例上一个实例:
看到前面的类关系图,是不是觉得很麻烦?是不是以为需要我们自己建立Subject以及Observer?但是其实没有这么麻烦哦!JDK中已经提供了对观察者模式的支持接口和类哦!java.util包中有Observable类和Observer接口,专用来支持观察者模式。
以更新天气预报为例(借鉴自《大话设计模式》中的一个例子)
2.1 Earth类(即Subject)
package designpatterns.observer;import java.util.Observable;/** * Created by Olive on 2017/10/14. */public class Earth extends Observable{ private String weather = "Sunny"; public String getWeather() { return weather; } public void setWeather(String weather) { this.weather = weather; // 设置状态变化 setChanged(); notifyObservers(weather); }}
在setWeather方法中调用了两个继承至Observable类的方法:
1. setChanged
/** * Marks this <tt>Observable</tt> object as having been changed; the * <tt>hasChanged</tt> method will now return <tt>true</tt>. */ protected synchronized void setChanged() { changed = true; }
setChanged方法很简单,就是将changed变量至为true(默认为false)。changed变量置为true才可以在接下来的notifyObservers(weather)方法中通知观察者
2. notifyObservers(weather)
/** * If this object has changed, as indicated by the * <code>hasChanged</code> method, then notify all of its observers * and then call the <code>clearChanged</code> method to indicate * that this object has no longer changed. * <p> * Each observer has its <code>update</code> method called with two * arguments: this observable object and the <code>arg</code> argument. * * @param arg any object. * @see java.util.Observable#clearChanged() * @see java.util.Observable#hasChanged() * @see java.util.Observer#update(java.util.Observable, java.lang.Object) */ public void notifyObservers(Object arg) { /* * a temporary array buffer, used as a snapshot of the state of * current Observers. */ Object[] arrLocal; synchronized (this) { /* We don't want the Observer doing callbacks into * arbitrary code while holding its own Monitor. * The code where we extract each Observable from * the Vector and store the state of the Observer * needs synchronization, but notifying observers * does not (should not). The worst result of any * potential race-condition here is that: * 1) a newly-added Observer will miss a * notification in progress * 2) a recently unregistered Observer will be * wrongly notified when it doesn't care */ if (!changed) return; arrLocal = obs.toArray(); clearChanged(); } for (int i = arrLocal.length-1; i>=0; i--) ((Observer)arrLocal[i]).update(this, arg); }
在上面这段代码中,为获取observer的方法做了同步,当检查changed状态为true时,将存储着observer的Vector(即obs)转化成了数组arrLocal,并将changed状态置为false。
随后遍历数组arrLocal进行update操作。
如此段代码的注释,此方法存在两个问题:1. 因为遍历观察者的方法不做同步,所以在同步方法后新加入的观察者,将会错过此次正在进行的通知 2. 同理,最近被删除的观察者也会被错误地通知。而此时,这个观察者已经不关注这个主题了。
2.2 Satellite类(天气卫星,即Observer)
package designpatterns.observer;import java.util.Observable;import java.util.Observer;/** * Created by Olive on 2017/10/14. */public class Satellite implements Observer{ private String weather; public void update(Observable o, Object arg) { weather = (String) arg; System.out.println(" Today's weather: " + weather); }}
Satellite实现了Observer接口,重写了update方法。
2.3来调用下天气情况吧~
package designpatterns.observer;/** * Created by Olive on 2017/10/14. */public class WeatherService { public static void main(String[] args){ Earth earth = new Earth(); Satellite satellite = new Satellite(); // 添加观察者 earth.addObserver(satellite); System.out.println("Weather report: "); earth.setWeather(" Sooooo Hot!!"); earth.setWeather(" Rain dogs and cats"); earth.setWeather(" Sunny~"); }}
2.4 输出结果
Weather report: Today's weather: Sooooo Hot!! Today's weather: Rain dogs and cats Today's weather: Sunny~
3. 一点小总结:
观察者模式的典型应用如下:1. 监听某个对象的状态变化 2. 发布者/订阅者模式中,当发布者发生变化,通知邮件中的订阅者。
观察者模式在具体实现时,根据系统设计时的不同需求,一般有两个不同的版本:推和拉。推模式——就是当主题发生改变时,主题主动将变化的信息推送给观察者。上述的例子就是推模式的一个应用。拉模式——当主题发生变化,仅仅只告诉观察者“主题发生变化”,若观察者想要知道具体的改变信息,需要主动从主题中“拉”出来。拉模式一般会把主题对象作为update()方法的入参,从而传递给观察者。当观察者需要获取具体变化信息时,可以通过主题对象的引用来获取。
那么推和拉模式有什么区别呢?
推模式将改变信息作为update方法的入参,所以如果我们要增加给观察者的信息时,要么提供新的update方法或者重新实现观察者,这样的情况是不易于扩展的;而拉模型将主题对象自身传递给观察者,让观察者自己去按需要取得信息,这样就不存在上述的问题。
当我们明确知道需要通知的信息时,我们可以使用推模式。而当我们不清楚观察者具体需要的信息时,可以使用拉模式。
- 设计模式—观察者模式
- 设计模式—观察者模式
- 设计模式—观察者模式
- 设计模式—观察者模式
- 设计模式—观察者模式
- 设计模式—观察者模式
- 设计模式—观察者模式
- 设计模式—观察者模式
- 设计模式—观察者模式
- 设计模式—观察者
- 设计模式——观察者设计模式
- 设计模式——观察者
- 设计模式——观察者
- 设计模式 —— 观察者
- 设计模式——观察者
- 【设计模式】——观察者
- 设计模式——观察者模式
- 每日设计模式——观察者模式
- 王学岗代理模式
- Android 简单断点续传|下载到本地
- HDOJ 1393 Weird Clock
- final
- 嵌入式c语言高级编程技巧 之 结构体的对象思维。
- 设计模式——观察者模式
- CSS盒子模型+浮动qing'chu+字体+背景
- Java 多线程核心技术梳理(附源码)
- 数据预处理总结
- 树和森林——树的同构
- Infogan-信息最大化生成对抗网络(理论部分)
- c++类和动态内存分配
- python练习题1 计算多个DNA序列中,GC比最高的序列
- LaTeX新人教程,30分钟从完全陌生到基本入门