zoukankan      html  css  js  c++  java
  • 事件和委托:第 5 页 委托、事件与Observer设计模式

    原文发布时间为:2008-11-01 —— 来源于本人的百度文章 [由搬家工具导入]

    委托、事件与Observer设计模式

    范例说明

    上面的例子已不足以再进行下面的讲解了,我们来看一个新的范例,因为之前已经介绍了很多的内容,所以本节的进度会稍微快一些:

    假设我们有个高档的热水器,我们给它通上电,当水温超过95度的时候:1、扬声器会开始发出语音,告诉你水的温度;2、液晶屏也会改变水温的显示,来提示水已经快烧开了。

    现在我们需要写个程序来模拟这个烧水的过程,我们将定义一个类来代表热水器,我们管它叫:Heater,它有代表水温的字段,叫做temperature;当然,还有必不可少的给水加热方法BoilWater(),一个发出语音警报的方法MakeAlert(),一个显示水温的方法,ShowMsg()。

    Observer设计模式简介

    上面的例子显然能完成我们之前描述的工作,但是却并不够好。现在假设热水器由三部分组成:热水器、警报器、显示器,它们来自于不同厂商并进行了组装。那么,应该是热水器仅仅负责烧水,它不能发出警报也不能显示水温;在水烧开时由警报器发出警报、显示器显示提示和水温。

    这时候,上面的例子就应该变成这个样子:      

    这里就出现了一个问题:如何在水烧开的时候通知报警器和显示器?在继续进行之前,我们先了解一下Observer设计模式,Observer设计模式中主要包括如下两类对象:

    • Subject:监视对象,它往往包含着其他对象所感兴趣的内容。在本范例中,热水器就是一个监视对象,它包含的其他对象所感兴趣的内容,就是temprature字段,当这个字段的值快到100时,会不断把数据发给监视它的对象。
    • Observer:监视者,它监视Subject,当Subject中的某件事发生的时候,会告知Observer,而Observer则会采取相应的行动。在本范例中,Observer有警报器和显示器,它们采取的行动分别是发出警报和显示水温。

    在本例中,事情发生的顺序应该是这样的:

    1. 警报器和显示器告诉热水器,它对它的温度比较感兴趣(注册)。
    2. 热水器知道后保留对警报器和显示器的引用。
    3. 热水器进行烧水这一动作,当水温超过95度时,通过对警报器和显示器的引用,自动调用警报器的MakeAlert()方法、显示器的ShowMsg()方法。

    类似这样的例子是很多的,GOF对它进行了抽象,称为Observer设计模式:Observer设计模式是为了定义对象间的一种一对多的依赖关系,以便于当一个对象的状态改变时,其他依赖于它的对象会被自动告知并更新。Observer模式是一种松耦合的设计模式

    实现范例的Observer设计模式

    我们之前已经对委托和事件介绍很多了,现在写代码应该很容易了,现在在这里直接给出代码,并在注释中加以说明。

    using System;
    using System.Collections.Generic;
    using System.Text;

    namespace Delegate {
           // 热水器
           public class Heater {
                  private int temperature;
                  public delegate void BoilHandler(int param);       //声明委托
                  public event BoilHandler BoilEvent;                     //声明事件

                  // 烧水
                  public void BoilWater() {
                         for (int i = 0; i <= 100; i++) {
                                temperature = i;

                                if (temperature > 95) {
                                       if (BoilEvent != null) {       //如果有对象注册
                                              BoilEvent(temperature);       //调用所有注册对象的方法
                                       }
                                }
                         }
                  }
           }

           // 警报器
           public class Alarm {
                  public void MakeAlert(int param) {
                         Console.WriteLine("Alarm:嘀嘀嘀,水已经 {0} 度了:", param);
                  }
           }

           // 显示器
           public class Display {
                  public static void ShowMsg(int param) {       //静态方法
                         Console.WriteLine("Display:水快烧开了,当前温度:{0}度。", param);
                  }
           }
          
           class Program {
                  static void Main() {
                         Heater heater = new Heater();
                         Alarm alarm = new Alarm();

                         heater.BoilEvent += alarm.MakeAlert;       //注册方法
                         heater.BoilEvent += (new Alarm()).MakeAlert;       //给匿名对象注册方法
                         heater.BoilEvent += Display.ShowMsg;              //注册静态方法

                         heater.BoilWater();       //烧水,会自动调用注册过对象的方法
                  }
           }
    }

    输出为:
    Alarm:嘀嘀嘀,水已经 96 度了:
    Alarm:嘀嘀嘀,水已经 96 度了:
    Display:水快烧开了,当前温度:96度。
    // 省略...

    // 热水器
    public class Heater {      
                  private int temperature;
                        
                  // 烧水
                  private void BoilWater() {
                         for (int i = 0; i <= 100; i++) {
                                temperature = i;
                         }
                  }
           }

           // 警报器
           public class Alarm{
                  private void MakeAlert(int param) {
                         Console.WriteLine("Alarm:嘀嘀嘀,水已经 {0} 度了:" , param);
                  }
           }

           // 显示器
           public class Display{
                  private void ShowMsg(int param) {
                         Console.WriteLine("Display:水已烧开,当前温度:{0}度。" , param);
                  }
    }

    namespace Delegate {
           class Heater {
                  private int temperature; // 水温

                  // 烧水
                  public void BoilWater() {
                         for (int i = 0; i <= 100; i++) {
                                temperature = i;

                                if (temperature > 95) {
                                       MakeAlert(temperature);
                                       ShowMsg(temperature);
                                }
                         }
                  }

                  // 发出语音警报
                  private void MakeAlert(int param) {
                         Console.WriteLine("Alarm:嘀嘀嘀,水已经 {0} 度了:" , param);
                  }
                 
                  // 显示水温
                  private void ShowMsg(int param) {
                         Console.WriteLine("Display:水快开了,当前温度:{0}度。" , param);
                  }
           }

           class Program {
                  static void Main() {
                         Heater ht = new Heater();
                         ht.BoilWater();
                  }
           }
    }

  • 相关阅读:
    yzoj P2344 斯卡布罗集市 题解
    yzoj P2350 逃离洞穴 题解
    yzoj P2349 取数 题解
    JXOI 2017 颜色 题解
    NOIP 2009 最优贸易 题解
    CH 4302 Interval GCD 题解
    CH4301 Can you answer on these queries III 题解
    Luogu2533[AHOI2012]信号塔
    Luogu3320[SDOI2015]寻宝游戏
    Luogu3187[HNOI2007]最小矩形覆盖
  • 原文地址:https://www.cnblogs.com/handboy/p/7148471.html
Copyright © 2011-2022 走看看