First Head 设计模式之观察者模式(Observer Pattern)

前言:

这一节开始学习观察者模式,开始讲之前会先像第一节那样通过一个应用场景来引入该模式。具体场景为:气象站提供了一个WeatherData对象,该对象可以追踪获取天气的温度、气压、湿度信息,WeatherData对象会随即更新三个布告板的显示:目前状况(温度、湿度、气压)、气象统计和天气预报。

1.    基本需求:利用WeatherData对象获取数据、并更新三个布告板:目前状况、气象统计和天气预报

WeatherData类图如下:

说明:

GetTemperature()、GetHumidity()、GetPressure()分别用来获取天气温度、湿度气压,MeasurementsChanged()当气象测量更新此方法会被调用。

分析:

  1. 可以通过WeatherData的Getter方法获取三个测量值:温度、湿度、气压
  2. 气象测量更新时会调用MeasurementsChanged()方法
  3. 需要实现三个天气数据布告板:“目前状况”、“气象统计”、“天气预报”,一旦WeatherData测到新值,这些布告也马上更新
  4. 此系统可扩展,可以随意的添加或者删除任何布告板。

实现:

public class WeatherData
{
    public void MeasurementsChanged()
    {
        float temp = GetTemperature();
        float humidity = GetHumidity();
        float pressure = GetPressure();
        currentConditionDisplay.update(temp, humidity, pressure);
        statisticsDisplay.update(temp, humidity, pressure);
        forecastDisplay.update(temp, humidity, pressure);
    }
    //其他方法
}

反思:

我们的这种实现有何不妥?

结合我们第一节中的一些面向对象的原则,这种实现方式会有如下问题:

l  针对具体实现编程,后续新增或者删除布告板必须修改程序

l  未将改变的地方封装起来

这种实现方式与面向对象的一些基本原则是相违背的,目前暂时是实现了用户的需求,但是在后续不具备可扩展行。

2.    引入观察者模式

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

出版者:就相当于“主题”(Subject),订阅者相当于“观察者”(Observer)

当出版者(主题)发行新的报纸的时候,所有的观察者(订阅者)就可以收到最新的报纸,同时,当新的观察者(订阅者)加入时,也可以收到最新的报纸,当观察者(订阅者)退订报纸后,就再也收不到新的报纸。

2.2 定义观察者模式

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

主题和观察者定义一对多的关系。观察者依赖于此主题,只要主题状态一有变化,观察者就会被通知,根据通知的风格,观察者可能因此新值而更新。

观察者模式:类图

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

松耦合的威力

当两个对象之间松耦合,它们依然可以交互,但是不清楚彼此的细节。

观察者模式提供了一种对象设计,让主题和观察者之间松耦合。

说明:

  1. 主题只知道观察者实现了某个接口(IObserver接口),不需要知道观察者是谁,或其他细节。
  2. 任何时候都可以增加或者删除的观察者,主题唯一依赖的是一个实现了IObserver接口的对象列表。
  3. 新的类型观察者出现时,主题代码不需要修改,只需要在新类型里实现观察者接口,然后注册为观察者即可。
  4. 可以独立的复用主题或观察者,因为二者松耦合。
  5. 改变主题或者观察者,并不会影响另一方。因为二者松耦合。

松耦合的设计之所以能让我们建立有弹性的OO系统,能够应对变化,是因为对象之间的相互依赖讲到了最低。

3.    利用观察者模式设计并实现气象站

3.1 设计气象站

类图:

3.2具体实现

3.2.1主题、观察者、显示接口
/// Description:对象、观察者、显示接口
    /// </summary>
    public interface ISubject
    {
        void RegisterObserver(IObserver o);//注册观察者
        void RemoveObserver(IObserver o);//删除观察者
        void NotifyObervers();//通知观察者
    }

    public interface IObserver
    {
        void Update(float temp, float humidity, float pressure);
    } 

    public interface IDisplayElement
    {
        void Display();
    }
3.2.2 WeatherData类:注册、删除、通知观察者
    /// Description:WeatherData 注册、删除、通知观察者
    /// </summary>
    public class WeatherData:ISubject
    {
        private ArrayList observers;
        private float temperature;
        private float humidity;
        private float pressure;

        public WeatherData()
        {
            observers = new ArrayList();//初始化obervers,用来存储注册的观察者
        }

        /// <summary>
        /// 注册观察者
        /// </summary>
        /// <param name="o"></param>
        public void RegisterObserver(IObserver o)
        {
            observers.Add(o);
        }

       /// <summary>
       /// 删除观察者
        /// </summary>
        /// <param name="o"></param>
        public void RemoveObserver(IObserver o)
       {
            int i = observers.IndexOf(o);
            if (i >= 0)
                observers.Remove(o);
        }

        /// <summary>
        /// 通知观察者
        /// </summary>
        public void NotifyObervers()
        {
            foreach (IObserver o in observers)
            {
                o.Update(temperature, humidity, pressure);
            }
        }

        /// <summary>
        /// 当从气象站得到更新观测值时,通知观察者
        /// </summary>
        public void MeasurementsChanged()
        {
            NotifyObervers();
        }

        /// <summary>
        ///
        /// </summary>
        /// <param name="temperature"></param>
        /// <param name="humidity"></param>
       /// <param name="pressure"></param>
        public void SetMeasurements(float temperature, float humidity, float pressure)
        {
            this.temperature = temperature;
            this.humidity = humidity;
            this.pressure = pressure;
            MeasurementsChanged();
        }
    }
3.2.3 布告板类,实现了IObserver、IDisplayElement接口

 

    /// Description:创建布告板
    /// </summary>
    public class CurrentConditionsDisplay:IObserver,IDisplayElement
    {
        private float temperature;
        private float humidity;
        private ISubject weatherData;

        public CurrentConditionsDisplay(ISubject weatherData)
        {
            this.weatherData = weatherData;
            weatherData.RegisterObserver(this);
        }

        public void Update(float temperature, float humidity, float pressure)
        {
            this.temperature = temperature;
            this.humidity = humidity;
            Display();
        }
        public void Display()
        {
            Console.WriteLine("Current coditions: " + temperature + "F degress and " + humidity + "% humidity");
        }
    }
3.2.4 测试
WeatherStation.WeatherData weatherData = new WeatherStation.WeatherData();
WeatherStation.CurrentConditionsDisplay currentDisplay = new WeatherStation.CurrentConditionsDisplay(weatherData);
weatherData.SetMeasurements(10, 20, 30);

结果如下:

4.   
Java内置的观察者模式

Java内置的观察者模式,许多功能都已经事先准备好了,甚至可以用推(push)或拉(pull)的方式传送数据。

使用java内置观察者模式实现气象站的OO设计类图,如下:

Java内置观察者模式与我们在3小节中明显的差异是WeatherData继承自Observable类,并集成了一些增加、删除、通知观察者的方法。

l  将对象变成观察者

首先还是要实现Observer(观察者)接口,其次调用Observable对象的addObserver()方法即可。

l  可观察者(主题)送出通知

  1. 先调用setChanged()方法,标记状态已经改变的事实。
  2. 调用notifyObservers()方法(该方法有2个,任意一个皆可):notifyObservers()或notifyObservers(Object arg)

l  观察者接收通知

观察者实现了Observer的接口,方法签名如下:

update(Observable o,Object arg)

第一个参数为主题本身,让观察者知道是哪个主题通知它的

第二个参数是传入notifyObservers()的数据对象

如果想用“推”的方式将数据给观察者,则可以把数据当做数据对象的方式传给notifyObservers(arg)

如果想用“拉”的方式将数据给观察者,则需要在update()中,通过WeatherData的getTemperature()等方法获取对应的气象值。

缺陷:

Java内置的观察者模式中Observable是一个类,你必须设计一个类去继承它。如果某类相同时具有Observable类和另一个超类的行为,就无法实现,因为java不支持多继承。

同时也限制了Observable的复用能力。

同时,Observable API将setChanged()方法保护了起来,除非继承自Observable类,否则无法创建Observable实例组合到自己的对象中,也违背了面向对象设计的第二个原则:多用组合,少用继承。

5.   
总结

OO原则:

封装变化

多用组合,少用继承

针对接口编程,不针对实现编程

对交互对象之间的松耦合设计而努力(新的OO原则,松耦合的设计更有弹性,更能应对变化)

OO模式:

观察者模式—在对象之间定义一对多的依赖,这样一来,当一个对象改变状态,依赖它的对象都会收到通知,并自动更新。

时间: 2025-01-01 14:01:23

First Head 设计模式之观察者模式(Observer Pattern)的相关文章

Java设计模式之观察者模式(Observer Pattern)

Observer Pattern 是一种常用的设计模式,它是一种事件监听模型.该模式有两个角色,一个是Subject, 另一个是Observer.Subject 保存有多个Observer的引用,一旦特定的事件发生,Subject会通知它所有的Observer,Observer得到该通知后执行相关程序逻辑.其中,Observer只有先向Subject注册后才能被Subject知晓.这就像订报纸,只有我们向出版社提出订报的申请,出版社才会把我们列入订阅者名单,然后每当新报纸印好时,出版社会通知订阅

【设计模式】观察者模式 Observer Pattern

定义:观察者模式定义了对象之间的一对多依赖.当“主题”(Object)状态改变事,所有依赖它的“观察者”(Observer)都会受到通知并自动更新.主题支持观察者订阅和退订. 观察者模式提供了一种对象设计,让主题和观察者之间松耦合.改变主题或观察者一方不会影响另一方.因为两者是松耦合的. 参考: 设计模式学习笔记--Observer Pattern观察者模式

设计模式 - 观察者模式(Observer Pattern) 详解

观察者模式(Observer Pattern) 详解 本文地址: http://blog.csdn.net/caroline_wendy/article/details/26583157 版权所有, 禁止转载, 如有转载, 请站内联系. 观察者模式(Observer Pattern): 定义了对象之间的一对多的依赖, 这样一来, 当一个对象改变状态时, 它的所有依赖者都会收到通知并自动更新. 使用方法: 1. 首先新建主题(subject)接口, 负责注册(register)\删除(remove

设计模式 - 观察者模式(Observer Pattern) Java内置 使用方法

观察者模式(Observer Pattern) Java内置 使用方法 本文地址: http://blog.csdn.net/caroline_wendy/article/details/26601659 观察者模式(observer pattern)详解, 参见: http://blog.csdn.net/caroline_wendy/article/details/26583157 Java内置的观察者模式, 是通过继承父类, 实现观察者模式的几个主要函数: Observerable(可被观

设计模式 - 观察者模式(Observer Pattern) 详细说明

观察者模式(Observer Pattern) 详细说明 本文地址: http://blog.csdn.net/caroline_wendy/article/details/26583157 版权全部, 禁止转载, 如有转载, 请站内联系. 观察者模式(Observer Pattern): 定义了对象之间的一对多的依赖, 这样一来, 当一个对象改变状态时, 它的全部依赖者都会收到通知并自己主动更新. 用法: 1. 首先新建主题(subject)接口, 负责注冊(register)\删除(remo

设计模式之观察者模式(Observer)摘录

23种GOF设计模式一般分为三大类:创建型模式.结构型模式.行为模式. 创建型模式抽象了实例化过程,它们帮助一个系统独立于如何创建.组合和表示它的那些对象.一个类创建型模式使用继承改变被实例化的类,而一个对象创建型模式将实例化委托给另一个对象.创建型模式有两个不断出现的主旋律.第一,它们都将关于该系统使用哪些具体的类的信息封装起来.第二,它们隐藏了这些类的实例是如何被创建和放在一起的.整个系统关于这些对象所知道的是由抽象类所定义的接口.因此,创建型模式在什么被创建,谁创建它,它是怎样被创建的,以

jQuery中的观察者模式(Observer Pattern)

在jQuery中,on方法可以为元素绑定事件,trigger方法可以手动触发事件,围绕这2个方法,我们来体验jQuery中的观察者模式(Observer Pattern). ■ on方法绑定内置事件,自然触发 比如,我们给页面的body元素绑定一个click事件,这样写. <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <title&

设计模式:观察者模式--Observer

一.什么是观察者模式 1.生活中的观察者模式 1.警察抓小偷 在现实生活中,警察抓小偷是一个典型的观察者模式「这以一个惯犯在街道逛街然后被抓为例子」,这里小偷就是被观察者,各个干警就是观察者,干警时时观察着小偷,当小偷正在偷东西「就给干警发送出一条信号,实际上小偷不可能告诉干警我有偷东西」,干警收到信号,出击抓小偷.这就是一个观察者模式 2.装模作样写作业 小时候家里家活比较多,爸妈让我去干活的时候,我偶尔会说我要学习「其实不想去干活,当然只是偶尔,我还是常常干家务的」,然后爸妈就去地里了,我一

设计模式之二:观察者模式(Observer Pattern)

先看下观察者模式的定义: The Observer Pattern defines a one-to-many denpendency between objects so that when one object changes state, all of its dependents are notified and updated automatically.:观察者模式定义了对象间一对多依赖关系,使得当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新. 观察者模式又叫发布-

Java设计模式模式观测(Observer Pattern)

Observer Pattern 设计模式通常用于.这是一个事件侦听器模型. 该模型有两个作用,一个是Subject, 有一个Observer.Subject 保存多个Observer参考,一旦一个特定的事件发生.Subject它会通知所有Observer.Observer得到该通知后运行相关程序逻辑. 当中,Observer仅仅有先向Subject注冊后才干被Subject知晓.这就像订报纸,仅仅有我们向出版社提出订报的申请,出版社才会把我们列入订阅者名单.然后每当新报纸印好时,出版社会通知订