观察者模式(Head First设计模式学习2)

1.1观察者模式定义

在给出观察者模式的定义之前,我们先来看个报纸和杂志的订阅是怎么回事:

1.报社的业务就是出版报纸

2.向某家报社订阅报纸,只有新报纸出版,报社才会送给你,只要你是用户,他就会一直向你发送。

3.当你不向看报纸了,取消订阅,他们就不会发送报纸。

4.只要报社还在运营,就会有人订阅报纸或取消报纸订阅

其实这个过程就和我们的观察者模式的过程相似。所以我们可以简单的将观察者模式定义为:

出版社+订阅者=观察者模式

这个毕竟是简单的,下面我们给出正式的定义:

观察者模式定义了对象之间的一对多依赖,当一个被依赖者改变状态时,他所有的依赖者都会收到通知并自动更新。

通过出版社和正式定义应该很容易理解观察者模式了。需要注意的是观察者模式定义了一些列对象之间的一对多的关系,当被依赖者改变状态时,其他的依赖者都会收到通知。

下面通过例子来看看观察者是怎么实现一对多依赖,以及如何通知多个依赖对象的。

1.2一个观察者模式的例子

这里我们使用head first设计模式的例子,某公司成功中标了气象站的项目。下面给出该项目的大致需求:

1、气象站会不定时的对天气状况(温度、湿度、气压)进行统计,并且封装在气象站提供的WeatherData对象中。

2、希望某公司能及时的提供目前的状况、气象统计、简单的预报,三种信息必须及时更新。

3、气象站还希望能该公司能提供一组API,好让其他公司能够根据三种信息的更新来做出其他的反应。

以上对应的需求说明图如下。

image

气象站给出了WeatherData对象部分代码提示,剩余的需要该公司去完善:

public double Temperture ;
public double Humidity ;

public double Pressure ;

public void MeasurementsChanged();//当温度湿度气压改变时作出的反应
public void OnChaged();//激发温度,湿度,气压反应的方法

1.2.1使用策略中的原则

我们利用策略模式中提到的原则,来完成该部分任务。先抽象出变化部分,进行封装(原则一),在此,显示器的种类会经常变化,并且其需要显示不同的状态,我们可以在此使用一个接口(IDisplay),用来显示,所以可以在里面定义个Display方法。

接着分析,如果气象站有温度,气压,湿度变化时,要去通知订阅的对象。这些对象可以是一个都是显示器,为了能在被依赖对象里实现统一的动作——更新,我们除了需要维护一个订阅者列表(原则三使用组合),还需要让依赖实现统一的接口(IOberver),其里面的方法为Update。(原则二面向接口编程)在update方法中调用Display。

Note:其实上面的Display和Update方法可以在一个接口中实现,这里为了保持清晰,就单独去实现各个方法。为了保持和书上的内容接近以及大家的常用命名,上面的统一接口我让他的名字定义成了IObserver,下面的被依赖对象接口我会把他定义为ISubject,分别对应观察者,主题。

1.2.2维护观察者模式列表

在被依赖对象的接口中,肯定会包括RegisterObserver(IObserver o),RemoveObserver(IObserver o),NotifyObserver(),在每一个显示器中有个ISubject对象,以便在构造时或者使用其他方法,将显示器添加到订阅列表。这样就不用在ISubject中去添加,直接调用ISubject对象的RegisterObserver(IObserver o),就可以添加了。

这样设计的一个好处时,实现了ISubject和IObserver之间的松耦合,在向订阅列表中添加订阅者时,不需要更改ISubject中的任何代码,只要主题和观察者都实现了自己对象的接口,各自更改自己的方法,相互不影响。除了上述好处外,无论是主题还是观察者,都各自可以不用依赖于对方存在于其他非观察者模式的场合。这些也是设计模式中常用的一个原则:

原则四:为交互对象之间的松耦合设计而努力。

有了松耦合,我们就可以更好的应对软件设计中的变化。让软件很有弹性。

下面给出其对应的UML:

image

可以看到subject和observer是通过依赖于抽象来解耦的,WeatherData依赖于多个IObserver,显示器依赖于ISubject(显示器的依赖我只表达出了一个)。具体的代码实现,我会在最后一并给出。

1.3观察者模式UML图

image

1.4源码

源代码中ObserverPatternUMLLib项目主要是关于WeatherData和显示器的设计。

1.5关于推和拉以及观察者模式与委托的联系

关于观察者模式中推和拉以及C#语言里面提供的委托事件可以参考下面两篇文章

http://kb.cnblogs.com/page/49989/

http://www.cnblogs.com/JimmyZhang/archive/2008/06/18/1225061.html

1.6小结

本文主要给出了观察者模式的定义,通过一个实例来熟悉观察者模式的松耦合思想。重点在于如何实现主题和观察者的一对多关系松耦合,以及如何实现观察者对主题的依赖。

原文地址:https://www.cnblogs.com/lzhp/p/3353647.html