zoukankan      html  css  js  c++  java
  • 设计模式(2):观察者模式-2 (委托、事件)

    一: 基本概念

    1、委托(Delegate)

    概念:对某个方法引用的一种引用类型变量。注意看概念, 委托是一种引用类型变量, 类型变量,因此可以将委托当作方法的参数进行传递。 通俗点来讲,委托有点像方法的快捷方式, 通过委托可以执行方法。

    声明: 在类中声明, 其声明决定了该委托可用的方法。也就是说,委托只可指向具有相同标签(参数、返回值)的方法。

    举个例子:

    1 // 声明委托
    2 public delegate double MyDelegate(string s);
    3 // 创建方法
    4 public double GetStart(string testString);
    5 // 实例化委托, 调用的方法需与委托有相同的参数、返回值
    6 MyDelegate delegate = new MyDelegate(GetStart);

    2、事件(Event)

    概念: 当某个类(发布者 Publisher)的某些特定状态改变时,发送通知给所有关心它这个变化的其它类(订阅者 Subscriber),并触发相关类中的相关函数。如按键、点击等都是事件。

    发布者: 决定什么时候触发事件。包含事件与委托的定义与声明,执行绑定了事件的方法(订阅者类中方法)。

    订阅者: 决定做什么事(提供具体方法)。 接受事件并提供事件处理程序的对象。

    事件声明:

    1 // 先声明事件的委托类型, 事件在生成时会调用委托
    2 public delegate void MyDelegateEventHandler(object sender, EventArgs e);
    3 public event MyDelegateEventHandler MyEvent;

    二、事件在观察者模式中的应用

    举一个《Head First 设计模式》 上的经典应用,附件上有完整的代码。

    需求如下: 建立一个气象观测站,该气象站建立在 WeatherData 对象上, 由 WeatherData 对象负责追踪目前的天气状况(温度、湿度、气压)。我们要建立一个应用,有三种(或更多)布告板, 分别显示目前的状况、气象统计以及简单的预报。当 WeatherDataObject 对象获得最新的测量数据时, 三种布告板必须实时更新。并且希望这个气象站的扩展性良好。

    1、创建发布者类

     1     // 发布者类
     2     public class WeatherData
     3     {
     4         // 声明事件
     5         public  delegate void WeatherChangeEventHandler(object sender, WeatherChangeArgs e);
     6         public event WeatherChangeEventHandler WeatherChange;
     7 
     8         // 虚函数,使得派生类可重写触发事件的标准
     9         protected  virtual void onWeatherChange(WeatherChangeArgs e)
    10         {
    11             WeatherChange?.Invoke(this, e);
    12         }
    13          // 事件一定要在方法中执行
    14         public  void RaiseWeatherChange(WeatherChangeArgs e)
    15         {
    16             onWeatherChange(e);
    17         }
    18     }
    19 
    20     // 创建一个事件类, 提供我们关心的数据的值
    21     public class WeatherChangeArgs : EventArgs
    22     {
    23         public  readonly double temperature;
    24         public  readonly double humidity;
    25         public  readonly double pressure;
    26         public WeatherChangeArgs(double temperature, double humidity, double pressure)
    27         {
    28             this.temperature = temperature;
    29             this.humidity = humidity;
    30             this.pressure = pressure;
    31         }
    32     }

    2、创建订阅者类

    订阅者数量众多,为了统一管理,需创建一个统一的接口,这也符合 OO 的原则, 面向接口编程。

     1 // 创建订阅者统一接口 
     2     public interface IWeatherStationSubject
     3     {
     4         void Display(object sender, WeatherChangeArgs e);
     5     }
     6 
     7 // 当前状况显示面板
     8   public class CurrentConditionDisplay : IWeatherStationSubject
     9     {
    10         public  void Display(object sender, WeatherChangeArgs e)
    11         {
    12             Console.WriteLine("Current conditons:" + e.temperature + "degreees and " + e.humidity + "% humidity" );
    13         }
    14     }
    15 // 未来预测天气状况显示面板
    16     public class ForecastDisplay : IWeatherStationSubject
    17     {
    18         public void Display(object sender, WeatherChangeArgs e)
    19         {
    20             Console.WriteLine("Tomorrow weather condition: " + e.temperature*1.1 + " degree ," + e.humidity*0.9 + "% humidity");
    21         }
    22     }
    23 
    24 // 个人情绪状态预测
    25     public class ForecastDisplay : IWeatherStationSubject
    26     {
    27         public void Display(object sender, WeatherChangeArgs e)
    28         {
    29             Console.WriteLine("Tomorrow weather condition: " + e.temperature*1.1 + " degree ," + e.humidity*0.9 + "% humidity");
    30         }
    31     }

    3、为了实现订阅系统与主控制系统松耦合, 创建订阅系统

    1     public class WeatherSubscriberSystem
    2     {
    3         public WeatherSubscriberSystem(WeatherData weatherData, WeatherChangeArgs e)
    4         {
    5             weatherData.WeatherChange += new WeatherData.WeatherChangeEventHandler((new CurrentConditionDisplay()).Display);
    6             weatherData.WeatherChange += (new ForecastDisplay()).Display;
    7             weatherData.WeatherChange += (new FeelingToneDisplay()).Display;
    8             weatherData.RaiseWeatherChange(e);
    9         }

     4、 主控制系统

     1   class Program
     2     {
     3         static void Main(string[] args)
     4         {
     5             WeatherSubscriberSystem sys_1 = new WeatherSubscriberSystem(new WeatherData(), new WeatherChangeArgs(20, 18.6, 55));
     6             Console.WriteLine("
    ");
     7             WeatherSubscriberSystem sys_2 = new WeatherSubscriberSystem(new WeatherData(), new WeatherChangeArgs(35, 24, 38));
     8             Console.ReadKey();
     9         }
    10     }

    至此整个系统完成了。我们可以发现,用 .net 内置的事件来实现观察者模式,比自己实现更简单,控制起来也更方便。

    点击下载完整代码

    参考:http://www.cnblogs.com/wudiwushen/archive/2010/04/21/1717378.html

  • 相关阅读:
    redis数据类型
    golang的select实现原理剖析
    goroutine的设计与实现
    go语言的duck typing
    go语言的局部变量在堆上还是栈上?
    REDIS学习
    C++11右值引用
    C++自问
    go语言interface学习
    go语言学习(基本数据类型)
  • 原文地址:https://www.cnblogs.com/yaolin1228/p/7690014.html
Copyright © 2011-2022 走看看