zoukankan      html  css  js  c++  java
  • C# 中的委托和事件详解(四)

    类似这样的例子是很多的,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度。
    // 省略...
    .Net Framework中的委托与事件尽管上面的范例很好地完成了我们想要完成的工作,但是我们不仅疑惑:为什么.Net Framework 中的事件模型和上面的不同?为什么有很多的EventArgs参数?
    在回答上面的问题之前,我们先搞懂 .Net Framework的编码规范:
    • 委托类型的名称都应该以EventHandler结束。
    • 委托的原型定义:有一个void返回值,并接受两个输入参数:一个Object 类型,一个 EventArgs类型(或继承自EventArgs)。
    • 事件的命名为 委托去掉 EventHandler之后剩余的部分。
    • 继承自EventArgs的类型应该以EventArgs结尾。
    再做一下说明:
    • 委托声明原型中的Object类型的参数代表了Subject,也就是监视对象,在本例中是 Heater(热水器)。回调函数(比如Alarm的MakeAlert)可以通过它访问触发事件的对象(Heater)。
    • EventArgs 对象包含了Observer所感兴趣的数据,在本例中是temperature。
    上面这些其实不仅仅是为了编码规范而已,这样也使得程序有更大的灵活性。比如说,如果我们不光想获得热水器的温度,还想在Observer端(警报器或者显示器)方法中获得它的生产日期、型号、价格,那么委托和方法的声明都会变得很麻烦,而如果我们将热水器的引用传给警报器的方法,就可以在方法中直接访问热水器了。
    现在我们改写之前的范例,让它符合 .Net Framework 的规范:
    using System;
    using System.Collections.Generic;
    using System.Text;

    namespace Delegate {
    // 热水器
    public class Heater {
    private int temperature;
    public string type = "RealFire 001"; // 添加型号作为演示
    public string area = "China Xian"; // 添加产地作为演示
    //声明委托
    public delegate void BoiledEventHandler(Object sender, BoiledEventArgs e);
    public event BoiledEventHandler Boiled; //声明事件

    // 定义BoiledEventArgs类,传递给Observer所感兴趣的信息
    public class BoiledEventArgs : EventArgs {
    public readonly int temperature;
    public BoiledEventArgs(int temperature) {
    this.temperature = temperature;
    }
    }

    // 可以供继承自 Heater 的类重写,以便继承类拒绝其他对象对它的监视
    protected virtual void OnBoiled(BoiledEventArgs e) {
    if (Boiled != null) { // 如果有对象注册
    Boiled(this, e); // 调用所有注册对象的方法
    }
    }

    // 烧水。
    public void BoilWater() {
    for (int i = 0; i <= 100; i++) {
    temperature = i;
    if (temperature > 95) {
    //建立BoiledEventArgs 对象。
    BoiledEventArgs e = new BoiledEventArgs(temperature);
    OnBoiled(e); // 调用 OnBolied方法
    }
    }
    }
    }

    // 警报器
    public class Alarm {
    public void MakeAlert(Object sender, Heater.BoiledEventArgs e) {
    Heater heater = (Heater)sender; //这里是不是很熟悉呢?
    //访问 sender 中的公共字段
    Console.WriteLine("Alarm:{0} - {1}: ", heater.area, heater.type);
    Console.WriteLine("Alarm: 嘀嘀嘀,水已经 {0} 度了:", e.temperature);
    Console.WriteLine();
    }
    }

    // 显示器
    public class Display {
    public static void ShowMsg(Object sender, Heater.BoiledEventArgs e) { //静态方法
    Heater heater = (Heater)sender;
    Console.WriteLine("Display:{0} - {1}: ", heater.area, heater.type);
    Console.WriteLine("Display:水快烧开了,当前温度:{0}度。", e.temperature);
    Console.WriteLine();
    }
    }

    class Program {
    static void Main() {
    Heater heater = new Heater();
    Alarm alarm = new Alarm();

    heater.Boiled += alarm.MakeAlert; //注册方法
    heater.Boiled += (new Alarm()).MakeAlert; //给匿名对象注册方法
    heater.Boiled += new Heater.BoiledEventHandler(alarm.MakeAlert); //也可以这么注册
    heater.Boiled += Display.ShowMsg; //注册静态方法

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

    输出为:
    Alarm:China Xian - RealFire 001:
    Alarm: 嘀嘀嘀,水已经 96 度了:
    Alarm:China Xian - RealFire 001:
    Alarm: 嘀嘀嘀,水已经 96 度了:
    Alarm:China Xian - RealFire 001:
    Alarm: 嘀嘀嘀,水已经 96 度了:
    Display:China Xian - RealFire 001:
    Display:水快烧开了,当前温度:96度。
    // 省略 ...
    总结
    在本文中我首先通过一个GreetingPeople的小程序向大家介绍了委托的概念、委托用来做什么,随后又引出了事件,接着对委托与事件所产生的中间代码做了粗略的讲述。
    在第二个稍微复杂点的热水器的范例中,我向大家简要介绍了 Observer设计模式,并通过实现这个范例完成了该模式,随后讲述了.Net Framework中委托、事件的实现方式。

    例子:

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

    namespace Delegate
    {
        /*
         * 老鼠出来找食物,正在抢食物时,其中一只老鼠突然发现了一只猫,于是叫了一声:猫来了,大家快跑.
         * 老鼠的叫声,引起了猫的注意.猫看到这么多美食,太开心了,于是也叫了一声.
         * 猫的叫声,吵醒了熟睡中的主人.于是主人说话了,并过去瞧个究竟.
         */
        class Mouse
        {
            public delegate void MouseDelegate(Object sender, MouseEventArgs e);//声明委托
            public event MouseDelegate callEventHandler;//声明事件

            private bool seeCat = false;//是否发现猫
            
            public class MouseEventArgs : EventArgs
            {
                public int mouseNumber = 10;
                public MouseEventArgs(int number)
                {
                    this.mouseNumber = number;
                }
            }

            public void Called(Object sender, MouseEventArgs e)
            {
                Console.WriteLine("老鼠惊叫:我发现猫来了,大家快跑...,于是 {0} 个老鼠一起抱头鼠窜",e.mouseNumber);
                Console.WriteLine("---------- 以上是老鼠的动作 -----------");
            }
            public void FindFood()
            {
                for(int i=10;i<24;i++)
                {
                    if(i==18)
                    {
                        Console.WriteLine("晚上18点,老鼠出来行走了....");
                    }
                    if (i == 20)
                    {
                        Console.WriteLine("晚上20点,老鼠正找食物....");
                    }
                    if (i == 21)
                    {
                        Console.WriteLine("晚上21点,老鼠找到食物,开始美美的享受美餐....");
                    }
                    if (i == 22)
                    {
                        Console.WriteLine("晚上22点,老鼠越来越多,食物不够分,引起轰抢....");
                    }
                    if (i == 23)
                    {
                        Console.WriteLine("正当老鼠抢得不可开交时,突然有一只老鼠发现了一只猫....");
                        seeCat = true;
                        break;
                    }
                }
                if (seeCat)
                {
                    MouseEventArgs e = new MouseEventArgs(10);
                    SeeCat(e);
                }
            }

            public virtual void SeeCat(MouseEventArgs e)
            {
                if (callEventHandler != null)
                {
                    callEventHandler(this, e);
                }
            }
        }

        class Cat
        {
            public void Hear(Object sender, Mouse.MouseEventArgs e)
            {
                Console.WriteLine("猫心里想:我听到老鼠的叫声了.嘿嘿,美餐来了!");
                Walking(e);
            }

            private void Walking(Mouse.MouseEventArgs e)
            {
                Console.WriteLine("猫飞快地朝老鼠发出声音的方向走去...");
                See(e);
            }

            private void See(Mouse.MouseEventArgs e)
            {
                Console.WriteLine("猫看到老鼠了.");
                Called(e);
            }

            private void Called(Mouse.MouseEventArgs e)
            {
                Console.WriteLine("猫欣喜若狂地说:哇!这么多只老鼠,我数数...天啊!一共有 {0} 只老鼠...", e.mouseNumber);
                Console.WriteLine("---------- 以上是猫的动作 -----------");
            }
        }

        class Human
        {
            public void Hear(Object sender, Mouse.MouseEventArgs e)
            {
                Called();
            }

            private void Called()
            {
                Console.WriteLine("主人说:这只死猫,还让不让人睡觉!看看去,到底是怎么了?");
                Walking();
            }

            private void Walking()
            {
                Console.WriteLine("go go go !");
                Console.WriteLine("---------- 以上是人的动作 -----------");
            }
        }

        class Program
        {
            static void Main()
            {
                Mouse m = new Mouse();
                m.callEventHandler += m.Called;
                Cat c = new Cat();
                m.callEventHandler += c.Hear;
                Human man = new Human();
                m.callEventHandler += man.Hear;
                m.FindFood();
                string a = Console.Read().ToString();
            }
        }
    }

     

  • 相关阅读:
    爱上你的一百个理由 (网摘)
    梦想向右,沉默向左
    明夕何夕,君已陌路。
    不肯嫁的几种男人(转)
    一剪梅
    C# preprocessor Directives
    Language
    C# Language Tour
    Web application
    Unsafe code
  • 原文地址:https://www.cnblogs.com/bicabo/p/1644336.html
Copyright © 2011-2022 走看看