• 观察者模式与.NET的delegate、event机制


    1.引言

             最近在写一些程序玩的时候,接触到了delegate(委托)和event(事件),网上查找了很多的资料,有些博文说可以把delegate近似当做C++当中的函数指针来看,由于自己本身对C++的理解并不是很透彻,所以看得仍然朦朦胧胧。今天上课学习了设计模当中的观察者模式。仔细学习之下,又对委托和事件有了新的体悟,特分享给大家。也希望能够与各位大虾多多交流。

    2.观察者模式介绍

    2.1概述

          观察者模式是建立一种对象与对象之间的依赖关系,一种对象发生改变时将自动通知其他对象,其他对象相应的做出反应。在观察者模式中,发生改变的对象称为观察目标,被通知对象称为观察者,一个观察目标可以对应多个观察者,而且这些观察者之间可以没有任何相互联系。就像在大街上,红灯亮起,来往的汽车停止,绿灯亮起,汽车可以继续前进,在这个过程中,交通信号是汽车的观察目标,大街上的汽车是观察者,并且大街上的每个汽车都是单独的个体没有相互之间的联系。

    2.2观察者模式的定义

    观察者模式:定义对象之间一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象都得到通知并被更新。

    Observer Pattern: Define a one-to-manydependency between objects so that when one object changes state , all itsdependts are notified and update automatically.

    2.3观察者模式结构

     观察者模式包含以下四个角色:

    (1)Subject(目标)

    (2)ConcreteSubject(具体目标)

    (3)Observer(观察者)

    (4)ConcreteObserve(具体观察者)

    2.4代码实例 

    using System.Collection
    
    
    //定义一个抽象目标类Subject
    
    abstract class Subject
    {
           //定义一个观察者集合用于存储所有观察者对象
          protected ArrayList observers = new ArrayList();
    
          //声明抽象注册方法,用于向观察者集合中增加一个观察者
          public abstract void Attach(Observer observer);
        
          //声明抽象的注销方法,用于在观察者集合中删除一个观察者
          public abstract void Detach(Oberver observer)
    
         //声明抽象通知方法
          public abstract void Notify();     
    }    
    
    //具体目标类ConcreteSubject 是实现了抽象目标类Subject的一个具体
    //子类,它实现了上述的3中方法
    
    class ConcreteSubject : Subject
    {
        public override void Attach(Observer observer)
        {
            observers.Add(observer);
        }
        
        public override void Detach(Observer observer)
        {
            observers.Remove(observer);
        }
        
        //实现通知方法
        public override void Notify()
        {
            //遍历观察者几何,调用每一个观察者的相应方法
            foreach (object obs in observers)
            {
                ((Observer)obs).Update();
            }
        }
        
        /*抽象观察者一般定义为一个借口,通常只声明一个Update()方法
         *为不同观察者的更新(相应)行为定义相同的借口,这个方法在其
         *子类中实现。
         */
         interface Observer
         {
            void Update();
         }
         
         //具体观察者ConcreteObserver中实现Update()方法
         class ConcreteObserver : Observer
         {
            //实现方法
            public void Update()
            {
            //具体更新代码
            }
         }
         static void Main(string[] args)
         {
            ...
            Subject subject = new ConcreteSubject();
            Observer observer = new ConcreteObserver();
            subject.Attach(observer);
            subject.Notify();
            ...
         }
    }

    3..NET中的delegate与event

    .NET中的委托事件模型是观察者模式在.NET中的经典应用,在WinForm编程中需要编写时间处理程序对所发生的事件(例如鼠标单击、菜单项选取等)做出反应,并执行相应的操作。事件被触发后,并执行响应该事件的一个或多个事件处理程序,可以将一个事件对象(例如按钮、文本框、菜单等)成为事件的发送者(事件源对象),接收并响应事件的对象称为时间的接收者(事件处理对象)。与观察这模式相对应,事件源对象充当观察目标角色,事件处理对象充当具体观察者角色,如果事件源对象的某个事件触发,则调用事件处理对象中的事件处理程序对事件进行处理。

    在.NETzhong ,如果需要从WinForm控件获取事件,提供一个委托(Delegate)类型的EventHandler,然后将它注册到事件源。在这里委托对象充当着抽象观察者的角色,所有事件处理方法都必须和委托方法具有相同的函数签名。

    eventSource.someEvent += new SomeEventHandler(someMethod);

    在该语法中,eventSource表示事件源,someEvent表示定义在事件源中的事件,someEventHandler表示用于处理事件的委托,someMethod表示与委托SomeEventHandler具有相同函数签名的事件处理方法。用户只需要修改someMethod,即可实现相同的时间对应不同的时间处理程序。

    在.NET事件中,事件源并不需要知道哪些对象或方会受到将要发生的通知,它只持有与签名相符合的方法的引用,即委托;还可以通过多重传送事件来实现一个事件有过个订阅者,即通过委托将多个方法添加到该事件中,当该事件被触发时,同时执行对应的多个事件处理方法。

    代码实例:

    using System;
    
    namespace ObserverExtend
    {
    	class EventTest
    	{
    		//定义一个委托
    		public delegate void UserInput(object sender, EventArgs e);
    		
    		//定义一个此委托类型的事件
    		public event UserInput OnUserInput;
    		
    		//模拟事件触发,当输入“0”时引发事件
    		public void Method()
    		{
    			bool flag = false;
    			Console.WriteLine("请输入数字:");
    			while(!flag)
    			{
    				if(Console.ReadLine() == "0")
    				{
    					OnUserInput(this ,new EventArgs());
    				}
    			}
    		}
    	}
    	
    	class Program
    	{
    		public Program(EventTest test)
    		{
    			//注册或订阅事件
    			test.OnUserInput += newEventTest.UserInput(Handler);
    			test.OnUserInput += newEventTest.UserInput(HandlerMore);
    			
    			//注销或取消订阅
    			//test.OnUserInput -= newEventTest.UserInput(Handler);
    		}
    		public void Handler(object sender,EventArgs e)
    		{
    			Console.WriteLine("数据输入结束!");
    		}
    		public void HandlerMore(object sender,EventArgs e)
    		{
    			Console.WriteLine("数据输入真的结束!");
    		}
    		
    		static void Main(string[] args)
    		{
    			EventTest test = new EventTest();
    			Program program = new Program();
    			tset.Method();
    		}
    	}
    }
    

      

    在类EventTest中定义了一个委托UserInput和一个事件 OnUserInput,EventTest充当观察目标类的角色而委托充当抽象观察者角色,在方法Method()中引发了事件,即调用与委托具有相同函数签名的方法,方法Method()即为目标类的通知方法。在客户端测试类Program中提供具体的时间处理方法,并将该方法和事件绑定在一起,这个过程称为订阅事件。
    在Program的构造函数中订阅事件,在此处,通过委托将两个方法添加到事件中,即该事件有两个订阅者,当事件触发时同时触发这些方法的执行,Program类充当具体观察者角色,可以对目标类的事件作出响应,方法Handler()和HandlerMore() 即为响应方法。

    4.感悟

    设计模式的学习让我提升了不少对C#的理解,记得有句话,有抱负的开发人员还需大力发扬钻研精神,不拘泥与可视化软件实际带来的便利之处,深入理解相关的技术细节,这是初级开发人员的必由之路。我们要会的不仅仅是拖一个Button。加油,与君共勉~

    5.参考资料

    http://www.cnblogs.com/wangjq/archive/2012/07/12/2587966.html

    《C#设计模式》刘伟 胡志刚 闫朝坤 清华大学出版社

  • 相关阅读:
    MySQL单机多实例安装并配置主从复制
    linux编译安装MySQL
    Mysql的float类型造成的困扰总结
    kettle初探
    最近的工作总结
    【spring boot】SpringBoot初学(7)– 多数据源及其事务
    【spring boot】SpringBoot初学(6)– aop与自定义注解
    【spring boot】SpringBoot初学(5)– WebService之Jersey
    SpringBoot初学(4)– JdbcTemplate和Mybatis
    【spring boot】SpringBoot初学(3)– application配置和profile隔离配置
  • 原文地址:https://www.cnblogs.com/MaFeng0213/p/5055326.html
Copyright © 2020-2023  润新知