今天有同事问我关于Observer模式的一个问题,说观察者(Observer)为什么要依赖于主题(Subject),如下图所示:
从上图可以看出,具体的观察者对具体的主题有一个依赖, 而且从JDK本身提供的Observer接口,我们也可以看到,确实对主题(在JDK的实现中,为Observable接口)有一个依赖,如代码所示:
public interface Observer {
void update(Observable o, Object arg);
}
这个是为什么呢,为什么这里会依赖主题对象?其实这个跟Subject与Observer之间通讯的方式有关,当Subject本身状态发生变化时,会去通知注册了的Observer(即调用每个observer的update()方法),那么这个时候,主题本身要怎么样去给Observer传输其需要的数据呢?
在我们看到的大多数观察者的实现中,主题(Subject)在通知注册的Observer时,都会把Observer所需要的数据封装好,传给Observer,这个也就是所谓的‘推’的模式,主题主动将数据推给观察者,这种情况下,Observer的接口往往定义如下:
public interface Observer {
void update(Object arg);//从主题传入的数据
}
在这种‘推’的模式下,观察者本身是不依赖于主题对象的。 但还有另外一种所谓‘拉’的通讯方式,是指观察者在需要数据的时候主动从主题对象中获取,这个情况下面就会出现观察者依赖于主题对象,
public interface Observer {
void update(Subject subject);
}
由于这种拉的实现方法出现的比较少,而且‘拉’数据的模式有一个比较大的缺点,那就是出现了主题对象和观察者对象之间的循环依赖,处理不好则很容易出来死循环。
但是对于一个完整的观察者模式来说,这两种数据传输的方式都是需要的,这也就是JDK的Observer接口中的update()方法要有两个参数的原因(Obervable对象一般对应于拉模式,Object对象一般对应于推模式),如果你做过Swing编程,你会发现在Swing的事件处理中,listner(实际上就是Observer)所接受的参数也支持推拉两种数据方式,如
public interface MouseListener extends EventListener {
public void mouseClicked(MouseEvent e);
。。。其他略
}
这里的MouseEvent对象实际上也包含了数据来源对象(触发事件的对象),即具体主题对象,而除了主题对象之外的其他属性,我们都可以看成是推模式中所传的数据。
好了,解决了同事了疑问,还需要点明Observer模式的另一职责。由于我们大多数的Observer模式的实现都很简单,在这样的实现下,主题对象大多只拥有一个职责,那就是管理Observer的职责(包括通知Observer),
class ConcreteSubject implement ISubject
{
private List observers=..
public void addObserver(Observer obs)
{
//add observer
}
public void removeObserver(Observer obs)
{
//remove observer
}
public void notifyObservers(Object obj)
{
//notify observers
}
}
加上Observer模式是为了解决一对多的关系,久而久之,导致大多数人都忘记了主题对象(Subject)本身还应该有另一个职责,管理Observer只是主题(Subject)对象应有的共同的职责,不要忘了,还有多主题对象这么一回事。举个以前看到的例子,
假设我们的主题对象需要从远程获取一些数据,并分别的将其记录在DB中,和显示在Screen上,那么套用Observer模式,可以表示为:
其中,DBObserver将拿到的数据写到DB中,而DisplayObserver将拿到的数据显示在SCREEN上,而MessagesSubject则有了两个职责,一个是我们前面说的管理Observer的职责,另一个是去远程取数据的职责,而这个我认为才是主题对象(Subject)应该有的具体的职责。
public class MessagesSubject extends AbstractSubject implements Runnable
{
//管理Observer的职责会从AbstractSuject中获得
//真正的业务逻辑
public void run()
{
//从远程获得messages
//通知观察者
}
完成一个完整的Observer模式很难,考虑的东西比较多(光是通知Observer这部分就有几种不同的实现方式),不推荐每次都需要实现一个很完整的Observer模式,但是我们不应该遗忘这些构成完整Observer模式锁需要的部分。
- 大小: 15.5 KB
- 大小: 3.9 KB
分享到:
相关推荐
Observer设计模式是一种经典的设计模式,在GOF 23种设计模式种 比较常用于实际。主要是有类指针传递并引用方法和消息传递响应的方法来实现。
observer观察者模式
NULL 博文链接:https://gary0416.iteye.com/blog/909427
这里面是我根据observer设计模式的原理,自己写的代码!希望能给大家带来帮助!!
请选用适当的设计模式,编写一个股票行情分析软件,随着时间的推移和股票价格的变动,实现各种指标的动态更新(要求至少实现一个股票的分时图和K线图:为降低编程工作量,K线图可以用开盘价、收盘价、最高价、最低价...
对Observer模式的实现,引入后可直接使用。 包括传统实现和遵循AOP思想的实现
23种设计模式之十六(行为模式)Observer模式
设计模式C++学习之观察者模式(Observer)
Head First模式设计用的是Java,实现观察者模式使用C++
设计模式体现的是一种思想,而思想则是指导行为的一切,理解和掌握了设计模式,并不是说记住了23种(或更多)设计场景和解决策略(实际上这也是很重要的一笔财富),实际接受的是一种思想的熏陶和洗礼,等这种思想...
C#面向对象设计模式纵横谈(19):(行为型模式) Observer 观察者模式 (Level 300)
在vc6.0中利用函数指针和接口两种方法实现observer模式的示例
设计模式之Observer模式,主动和被动的通知一系列对象要做某事。
Observer与Command模式在VTK类库设计中的应用研究 通过阅读本文档可以熟悉vtk中的重要编程模式
我们说学习Java应该从Swing开始,那么学习Swing最重要的思想就是对于观察者模式的理解(Observer Pattern)。因为,该设计模式在Java Swing框架中贯穿了始终。对于C#的委托、代理概念所使用的Callback(回调模式--...
实际上,不使用委托和事件,一样可以实现Observer模式。在本文中,我将使用GOF的经典方式,再次实现一遍Observer模式,同时将讲述在 C#中的委托和事件 一文中没有提及的推模式(Push)和拉模式(Pull)。
观察者模式示例 观察者模式示例 观察者模式示例 观察者模式示例 观察者模式示例 观察者模式示例
观察者模式中推拉模式两种实现方式,主要是针对开发的一个项目的模型抽象出来的。有一个项目,有压力传感器、位移传感器、震动传感器等多种传感器每种类型有若干个传感器,对每个传感器做特定操作会引发历史曲线图、...
C#面向对象设计模式 (行为型模式) Observer 观察者模式 视频讲座下载
观察者模式 概述 定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。 适用性 1.当一个抽象模型有两个方面,其中一个方面依赖于另一方面。 将这二者封装...