复习委托事件

  人一安逸就不思进取,找打工作后就没有以前那么认真了,人也变懒了,用不着的不学不练。想学学构架方面的知识,看着看着就发现以前不少基本的东西都生疏了。比如看到观察者模式的时候就像不太清楚委托事件的知识了,所以找了点文章复习下。

  委托是一种数据结构,是一种类型,引用类型,能够引用静态方法或者实例的方法,类似于C的函数指针,可以把方法当着参数传递,在很多地方避免了进行更过的判断。

  事件是实例,其实是对委托的进一步封装,其实例化了一个私有的委托对象,通过add()和remove()来注册和注销事件,以防止在实例外部能主动的触发注册的事件,而达到只能在事件的发布者内部决定是否要触发事件的目的。等于对委托的进一步阉割。

  下面例子的环境是模拟用户订阅彩票发布机构,用户订阅彩票中奖号码发布机构的发布中奖号码这件事(就是订阅者对这件事情感情兴趣),当发布中奖号码事件触发,用户就能知道自己是否中奖。

  彩票中奖信息发布结构。

    //彩票中奖号码发布机构
    public class LotteryPublisher
    {
        //声明发布中奖号码事件的委托
        public delegate void PublisherHander(string _Number);
        //建立发布中奖号码事件
        public event PublisherHander OnPublisher;
        //触发事件方法(发布中奖信息)
        public void Trigger()
        {
            string num = GetNumber();
            if (OnPublisher != null)
            {
                Console.WriteLine("本期中奖号码为{0}", num);
                OnPublisher(num);
            }
        }
        //摇号(随机产生九位数字)
        private string GetNumber()
        {
            string num = "";
            Random random = new Random();
            for (int i = 0; i < 9; i++)
            {
                num += random.Next(9).ToString();
            }
            return num;
        }
    }

  购买彩票的用户。

public class Client
    {
        //客户姓名
        private string name = "";
        //客户自己选的号码
        private string myNumber = "";
        public Client(string number,string name)
        {
            this.myNumber = number;
            this.name = name;
        }
        //要注册的方法,查看自己是否中奖
        public void Check(string number)
        {
            if (myNumber == number)
            {
                Console.WriteLine("{0}:哦也,我中奖了,哈哈哈!!!",name);
            }
            else
            {
                Console.WriteLine("{0}:TMD小日本,又没中~~~",name);
            }
        }
    }

  接下来摇奖开始。

class Program
    {
        static void Main(string[] args)
        {
            LotteryPublisher pub = new LotteryPublisher();//实例化彩票摇奖器对象
            Client client1 = new Client("9657412355","张三");
            Client client2 = new Client("8516541558","李四");
            pub.OnPublisher += new LotteryPublisher.PublisherHander(client1.Check);
            pub.OnPublisher += new LotteryPublisher.PublisherHander(client2.Check);
            //摇奖开始
            Console.WriteLine("摇奖开始");
            pub.Trigger();
            Console.ReadKey();
        }
    }

  平时我们在网页上或者WinForm窗体上拖上一个button,然后双击,就能生成这样一段代码

 private void button1_Click(object sender, EventArgs e)
{
      //自定义的事件处理代码  
}

我们可以看到其中有两个参数,分别是 sender和e,如果加个断点就能发现sernder就是触发事件的对象,这里也就那个button,而e就是事件感兴趣的对象,这里就是button的X,Y坐标之类的。接下来说下微软对委托事件的.Net Framework的编码规范。

1、委托类型的名称都应该以EventHandler结束。 
2、委托的原型定义:有一个void返回值,并接受两个输入参数:一个Object 类型,一个 EventArgs类型(或继承自EventArgs)。 
3、事件的命名为 委托去掉 EventHandler之后剩余的部分。 
4、继承自EventArgs的类型应该以EventArgs结尾。

  我们现在按照微软的编码规范再改造下我们的程序

订阅者所感兴趣的事情(摇奖产生的中奖号码)
 //订阅者所感兴趣的事情(摇奖产生的中奖号码)
    public class NumberEventArgs : EventArgs
    {
        //摇奖产生的中奖号码
        private string number;

        public string Number
        {
            get { return number; }
            set { number = value; }
        }
        public NumberEventArgs(string _number)
        {
            Number = _number;
        }
    }

  彩票中奖号码发布机构。

public class LotteryPublisher
    {
        //声明发布中奖号码事件的委托
        public delegate void PublisherEventHander(object sender,NumberEventArgs e);
        //建立发布中奖号码事件
        public event PublisherEventHander Publisher;
        //触发事件方法(发布中奖信息)
        protected void OnPublisher(NumberEventArgs e)
        {
            if (Publisher != null)
            {
                Console.WriteLine("本期中奖号码为{0}", e.Number);
                Publisher(this,e );
            }
        }
        public void Trigger()
        {
            OnPublisher(new NumberEventArgs(GetNumber()));
        }
        //摇号(随机产生九位数字)
        private string GetNumber()
        {
            string num = "";
            Random random = new Random();
            for (int i = 0; i < 9; i++)
            {
                num += random.Next(9).ToString();
            }
            return num;
        }
    }

  购买彩票客户。

//购买彩票客户
    public class Client
    {
        //客户姓名
        private string name = "";
        //客户自己选的号码
        private string myNumber = "";
        public Client(string number, string name)
        {
            this.myNumber = number;
            this.name = name;
        }
        //要注册的方法,查看自己是否中奖
        public void Check(object sender, NumberEventArgs e)
        {
            if (myNumber == e.Number)
            {
                Console.WriteLine("{0}:哦也,我中奖了,哈哈哈!!!", name);
            }
            else
            {
                Console.WriteLine("{0}:又没中~~~", name);
            }
        }
    }

  最后开始摇奖。

 static void Main(string[] args)
        {
            LotteryPublisher pub = new LotteryPublisher();//实例化彩票摇奖器对象
            Client client1 = new Client("9657412355","张三");
            Client client2 = new Client("8516541558","李四");
            pub.Publisher += new LotteryPublisher.PublisherEventHander(client1.Check);
            pub.Publisher += new LotteryPublisher.PublisherEventHander(client2.Check);
            //摇奖开始
            Console.WriteLine("摇奖开始");
            pub.Trigger();
            Console.ReadKey();
        }

  有了委托机制我们就能把方法当成参数来传递,而委托和事件结合,我们就能再出事件发布者内部定义好特定的逻辑,而在这逻辑中细节实现依赖于事件订阅者的处理逻辑,当我们把事件订阅者处理逻辑的方法以注册事件的方法(就是传递方法的委托)传递到事件订阅者内部,就能实现我们的整个功能。

  现在看看上面的代码有没有一种很熟悉的感觉~~,其实.net中委托事件是对观察者模式的一种原生支持,其背后就是观察者模式(Observer)。

posted @ 2012-09-19 16:20  在路上—书生  阅读(356)  评论(0编辑  收藏  举报