委托(二):使用事件来对委托变量进行封装

接上篇:委托(一):委托与方法

在以前学习设计模式的时候,我们经常看到这样的代码:

可以这样说,委托和事件经常一起使用,感觉挺麻烦的,而且觉得委托已经挺好了,为什么还要加入事件呢?搞得挺复杂的。ok,下面来通过个小例子来说明为什么要使用事件。

例子中各个类结构如图(我们将上篇博文的实例进行了改进,把方法分散到不同的类中,尽量模拟实际调用时的情况):

首先是最简单的GreetingMethod类代码:

namespace 委托和事件
{
   public  class GreetingMethod
    {
        /// <summary>
        /// 英语的说早上好的方法
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public static void EnglishGreeting(string name)
        {
            Console.WriteLine("good,morning!" + name);

        }

        /// <summary>
        /// 汉语的问好方法
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public static void ChineseGreeting(string name)
        {
            Console.WriteLine("早上好,宝贝儿~~~" + name);

        }

    }
}

在GreetingMethod类中,我们将具体的Greeting方法放在了这个类中,这里先不考虑以后的变化因素。

接着是GreetingManager类,在这个类里面,我们将原先的GreetPeople方法搬移到这个类里面:

namespace 委托和事件
{
    //委托的定义
    //1,委托:委托出现的位置和string相同,所以GreetingDelegate应该也是个类型,但是委托的声明方式和类完全不同。
    //2,委托在编译的时候确实会被编译成类,因为delegate是一个类,所以在任何可以生命类的地方都可以声明委托。
    public delegate void GreetingDelegate(string name);

    /// <summary>
    /// 管理方法调用的类
    /// </summary>
    public class GreetingManager
    {
        #region 在类内部定义委托变量

            ////第一次改进:在GreetingManager类的内部声明delegate1变量
            //public GreetingDelegate delegate1;

        #endregion

        #region 使用event

            public event GreetingDelegate MakeGreet;

        #endregion

        //使用了委托之后,对GreetPeople方法进行的改进

        #region 将委托作为方法的参数传递到函数里
        ///// <summary>
        ///// 调用问候方法
        ///// </summary>
        ///// <param name="name">姓名</param>
        ///// <param name="MakeGreeting">具体调用的方法名称</param>
        //public void GreetPeople(string name, GreetingDelegate MakeGreeting)
        //{
        //    MakeGreeting(name);

        //}
        #endregion

        #region 在方法内部直接调用成员变量delegate1

            //public void GreetPeople(string name)
            //{
            //    if (delegate1 != null) {  //如果委托变量已被赋值
            //        delegate1(name);  //那么直接调用
            //    }
            //}
        #endregion

        #region 使用event

            public void GreetPeople(string name)
            {
                MakeGreet(name);

            }

        /***
         * MakeGreet事件的声明与之前的委托变量delegate1的声明唯一的区别就是多了一个event关键字。
         *
         * so..........
         *
         * 1,声明一个事件不过类似于声明一个进行了封装的委托类型的变量而已。
         *
         * 2,event对委托变量进行了封装,类似于以前的get,set字段
         *
         *
         *
         * ***/
        #endregion

    }
}

接着是客户端的调用:

namespace 委托和事件
{
    class Program
    {
        static void Main(string[] args)
        {

            #region 将GreetingManager放入其他类中之后客户端调用

                //GreetingManager manager = new GreetingManager();
                //manager.GreetPeople("水田如雅", GreetingMethod.EnglishGreeting);
                //manager.GreetPeople("vac", GreetingMethod.ChineseGreeting); 

            #endregion

            #region 多个方法绑定同一个委托变量

                //GreetingManager manager = new GreetingManager();

                //GreetingDelegate delegate1;
                //delegate1 = GreetingMethod.EnglishGreeting;
                //delegate1 += GreetingMethod.ChineseGreeting;

                //manager.GreetPeople("水田如雅", delegate1);

            #endregion

            #region 在GreetingManager类内部声明委托后客户端调用示例

                //GreetingManager gm = new GreetingManager();
                //gm.delegate1 = GreetingMethod.EnglishGreeting;
                //gm.delegate1 += GreetingMethod.ChineseGreeting;

                //gm.GreetPeople("水田如雅",gm.delegate1);

            //PS:尽管这样做没有任何问题,但是这条语句很奇怪,在调用gm.GreetPeople("水田如雅",gm.delegate1);方法的时候,再次传递了gm的delegate1字段;但是delegate1本身就在gm中。所以这里需要再次改进。

            #endregion

            #region 改进GreetingManager类的GreetPeople方法之后的调用

                //GreetingManager gm = new GreetingManager();
                //gm.delegate1 = GreetingMethod.EnglishGreeting;
                //gm.delegate1 += GreetingMethod.ChineseGreeting;

                //gm.GreetPeople("水田如雅");//这次调用的时候,直接传入name,不再需要传入delegate了

            #endregion

            #region 继续思考,thinking............

            /*
             * 虽然取得了想要的效果,但是还是存在问题。
             * 1,在这里,delegate1和平时用的string类型的变量并没有什么分别,并不是所有的成员变量都应该声明为public,按照信息隐蔽的原则,我们应当尽量封装数据。
             * 2,但是如果将delegate1声明为private,那么,我们如何为它赋值呢?如果不能赋值,如何注册方法呢?
             * 3,delegate1声明为了public,则可以对他进行任意修改,破坏了封装性。
             *
             *
             * 4,解决上述问题的方法,使用event...............

             */
            #endregion

            #region 使用了event之后的调用

                //GreetingManager gm = new GreetingManager();

                ////注意使用时,第一次也是“+=”,不同于直接使用委托
                //gm.MakeGreet += GreetingMethod.EnglishGreeting;
                //gm.MakeGreet += GreetingMethod.ChineseGreeting;

                //gm.GreetPeople("水田如雅");

            #endregion

        }
    }
}

接下来来描述下我们对这个小Demo的改进过程:

使用委托,我们主要是为了达到【方便】【安全】的调用方法。

为了方便的调用,我们先是将在GreetingManager类的内部声明delegate1变量,之后发现了这样做,

在调用上述方法的时候,又要在本类的方法中将本类的成员变量赋值给本类的方法,这样做很奇怪,为什么不直接就在这个类的方法内部直接调用它的成员变量呢,于是我们就去掉了上述方法中第二个参数,但是这样还是有问题,就是类成员的访问问题。

原则上来说,我们应当尽量降低类成员的访问权限,来达到封装效果,但是现在,我们直接就在客户端赋值了本该封装的成员变量。

为了解决这个问题,我们回想下,以前我们是如何隐藏字段的:

yes,我们使用property来对内部的的private成员变量进行访问控制。

但是对于delete的访问控制,似乎更简单,我们在声明委托的时候,顺便在前面加上个event就ok了:

这样,就变相完成了访问控制的作用。

   小结:

总结下引入event的好处:

1,event封装了委托类型的变量,相当于为委托类型量身定制的属性(property)。

2,使用事件不仅能获得比委托更好地方封装性,还能限制含有事件的类型的能力。

时间: 2024-10-24 17:23:38

委托(二):使用事件来对委托变量进行封装的相关文章

.NET进阶篇-语言章-2-Delegate委托、Event事件

知识只有经过整理才能形成技能 整个章节分布简介请查看第一篇 内容目录 一.概述 二.解析委托知识点 1.委托本质 2.委托的使用 3.委托意义 逻辑解耦,减少重复代码 代码封装支持扩展 匿名方法和Lambda表达式 异步多线程 多播委托 三.事件 四.总结 一.概述 先说下委托,委托我们也经常用到.详尽了解委托是必要的,不然在异步多线程的编程中会一头雾水.委托本质就是一个类,和我们平常定义的类没多大区别.只是这个类的作用的是描述一些方法,没有数据成员.一个委托定义了一类拥有同样返回类型和参数的方

事件委托和JQ事件绑定总结

事件委托: 比喻:事件委托的事例在现实当中比比皆是.比如,有三个同事预计会在周一收到快递.为签收快递,有两种办法:一是三个人在公司门口等快递:二是委托给前台MM代为签收.现实当中,我们大都采用委托的方案(公司也不会容忍那么多员工站在门口就为了等快递).前台MM收到快递后,她会判断收件人是谁,然后按照收件人的要求签收,甚至代为付款.这种方案还有一个优势,那就是即使公司里来了新员工(不管多少),前台MM也会在收到寄给新员工的快递后核实并代为签收. 实现原理:我们知道,DOM在为页面中的每个元素分派事

JS中事件代理与委托

在javasript中delegate这个词经常出现,看字面的意思,代理.委托.那么它究竟在什么样的情况下使用?它的原理又是什么?在各种框架中,也经常能看到delegate相关的接口.这些接口又有什么特殊的用法呢?这篇文章就主要介绍一下javascript delegate的用法和原理,以及Dojo,jQuery等框架中delegate的接口. JavaScript事件代理 首先介绍一下JavaScript的事件代理.事件代理在JS世界中一个非常有用也很有趣的功能.当我们需要对很多元素添加事件的

委托、Lambda表达式、事件系列04,委托链是怎样形成的, 多播委托

在"委托.Lambda表达式.事件系列01,委托是什么,委托的基本用法,委托的Method和Target属性"中,反编译委托,发现委托都是多播委托. 既然委托是多播委托,我们可以通过"+="把多个方法赋给委托变量,这样就形成了一个委托链, 它是怎样形成的?来看下面的例子: namespace ConsoleApplication3 { internal delegate void MySayDel(string msg); class Program { stati

javascript 事件委托 和jQuery事件绑定on、off 和one

一. 事件委托什么是事件委托?用现实中的理解就是:有100 个学生同时在某天中午收到快递,但这100 个学生不可能同时站在学校门口等,那么都会委托门卫去收取,然后再逐个交给学生.而在jQuery 中,我们通过事件冒泡的特性,让子元素绑定的事件冒泡到父元素(或祖先元素)上,然后再进行相关处理即可.如果一个企业级应用做报表处理,表格有2000 行,每一行都有一个按钮处理.如果用之前的.bind()处理,那么就需要绑定2000 个事件,就好比2000 个学生同时站在学校门口等快递,不断会堵塞路口,还会

JavaScript事件代理和委托

在javasript中delegate这个词经常出现,看字面的意思,代理.委托.那么它究竟在什么样的情况下使用?它的原理又是什么?在各种框架中,也经常能看到delegate相关的接口.这些接口又有什么特殊的用法呢?这篇文章就主要介绍一下javascript delegate的用法和原理,以及Dojo,jQuery等框架中delegate的接口. JavaScript事件代理 首先介绍一下JavaScript的事件代理.事件代理在JS世界中一个非常有用也很有趣的功能.当我们需要对很多元素添加事件的

VB.net学习笔记(二十三)再识委托

一.调用静态方法 1.声明 委托须使用前声明定义,可以带参数(一个或多个),可以有返回值. '位于一个模块或类的声明部分 Delegate Sub OneArgSub{ByVal msg As String) '带一个参数,且无返回类型 定义了一个委托的类.后台创建了一个名为OneArgSub的新类,这个类是从System.Delegate类继承而来的.(更准确地说从 Systetn.MuhicastDelegate 继承而来的,而 System.MulticastDelegate 则又是从 S

javascript事件委托和jQuery事件绑定on、off 和one

一. 事件委托什么是事件委托?用现实中的理解就是:有100 个学生同时在某天中午收到快递,但这100 个学生不可能同时站在学校门口等,那么都会委托门卫去收取,然后再逐个交给学生.而在jQuery 中,我们通过事件冒泡的特性,让子元素绑定的事件冒泡到父元素(或祖先元素)上,然后再进行相关处理即可.如果一个企业级应用做报表处理,表格有2000 行,每一行都有一个按钮处理.如果用之前的.bind()处理,那么就需要绑定2000 个事件,就好比2000 个学生同时站在学校门口等快递,不断会堵塞路口,还会

js事件捕获,事件冒泡,事件委托以及DOM事件流

一:DOM事件流: 事件流是从页面接收事件的顺序,DOM2级事件规定事件流包括三个阶段: ①事件捕获阶段:用意在于事件达到目标之前捕获它,在事件捕获阶段事件流模型:document→html→body→div ②处于目标阶段2:实际的目标到事件 ③事件冒泡阶段:由最具体的元素接收到事件,然后向上传播到较为不具体的节点.事件流模型:div →body→ html→ document 二:事件委托 事件委托顾名思义:将事件委托给另外的元素.其实就是利用DOM的事件冒泡原理,将事件绑定到目标元素的父节

整理之DOM事件阶段、冒泡与捕获、事件委托、ie事件和dom模型事件、鼠标事件

整理之DOM事件阶段 本文主要解决的问题: 事件流 DOM事件流的三个阶段 先理解流的概念 在现今的JavaScript中随处可见.比如说React中的单向数据流,Node中的流,又或是今天本文所讲的DOM事件流.都是流的一种生动体现.用术语说流是对输入输出设备的抽象.以程序的角度说,流是具有方向的数据. 事件流分事件冒泡与事件捕获 在浏览器发展的过程中,开发团队遇到了一个问题.那就是页面中的哪一部分拥有特定的事件? 可以想象画在一张纸上的一组同心圆,如果你把手指放在圆心上,那么你的手指指向的其