委托的定义及使用

介绍

  首先委托是对方法进行封装的一个类,它将方法作为参数来调用。

  下面来简单看看委托的三部曲,委托的声明,实例化,调用,代码如下:

 1 class DelegeteTest
 2     {
 3         public delegate void DelegateShow(); //声明
 4         public void Show()
 5         {
 6             {
 7                 //普通调用
 8                 DoSomething();
 9             }
10             {
11                 DelegateShow delegateShow = new DelegateShow(DoSomething); //实例化,方法作为参数传递
12                 delegateShow(); // 委托调用
13             }
14             //委托将方法包装成了一个对象
15         }
16 
17         /// <summary>
18         /// 普通方法
19         /// </summary>
20         public void DoSomething()
21         {
22             Console.WriteLine("this is doSomething");
23         }
24     }

  这是一个简单的委托,那么为什么要这样使用委托呢?这里我引入一个简单的例子,请看下面的代码:

 1  public class People
 2     {
 3         /// <summary>
 4         /// 对某人的简单的问候
 5         /// </summary>
 6         public void SayHI(string Name)
 7         {
 8             Console.WriteLine("你好,{0}", Name);
 9         }
10     }
11 
12   
13     {
14             People p = new People();
15             p.SayHI("张三");
16     }

这里新建一个People 类 实现一个简单的问候方法。随着程序的运行,我们的需求可能会发生变化(唉,需求变化乃万恶之源)。

 这里我们扩展一下。我们的问候对象 要区分中国人,美国人,日本人,方法就要改对应国家的语言。一般我们对原有的方法作出以下修改。

public class People
    {
        /// <summary>
        /// 对多国家的人进行问候
        /// </summary>
        public void SayHI(string Name,PeopleType peropleType)
        {
            if (peropleType == PeopleType.Chinese)
            {
                Console.WriteLine("你好,{0}", Name);
            }
            else if (peropleType == PeopleType.American)
            {
                Console.WriteLine("Hello,{0}", Name);
            }
            else if (peropleType == PeopleType.Japanese)
            {
                Console.WriteLine("&*%$%^%$^,{0}", Name);
            }
        }

        public enum PeopleType
        {
            Chinese=0,
            American=1,
            Japanese=2
           
        }
    }

//---------------------------------------------------------------------------------------
            {
                People p = new People();
                p.SayHI("张三", People.PeopleType.Chinese);
                p.SayHI("Tom", People.PeopleType.American);
                p.SayHI("漩涡鸣人", People.PeopleType.Japanese);
            }

  这样做虽然实现了功能,但是这样做不推荐,因为每增加一个分支(比如又新加了法国人,韩国人等等),都需要去修改SayHI()方法和新增一个PeopleType。这样系统耦合性太大,SayHI方法包法了所有的问候逻辑。于是我们继续升级,代码如下:

/// <summary>
        /// 对中国人的问候
        /// </summary>
        /// <param name="Name"></param>
        public void SayHIChinese(string name)
        {
            Console.WriteLine("你好,{0}", name);
        }

        /// <summary>
        /// 对美国人的问候
        /// </summary>
        /// <param name="name"></param>
        public void SayHIAmerican(string name)
        {
            Console.WriteLine("Hello,{0}", name);
        }

        /// <summary>
        /// 对日本人的问候
        /// </summary>
        /// <param name="name"></param>
        public void SayHIJapanese(string name)
        {
            Console.WriteLine("&*%$%^%$^,{0}", name);
        }


     Console.WriteLine("-----------升级---------");
            {
                People p = new People();
                p.SayHIChinese("张三丰");
                p.SayHIAmerican("Jerry");
                p.SayHIJapanese("旗木卡卡西");
            }

  这样我们把原来分支里面的拆分成上面的多个方法。这样就可以适应人物类型的扩展了,看似没有什么问题。这时我们的问题来了,我们的业务要进行扩展。我们需要在每次问候之前,结束都需要加入日志记录。代码如下:

 1 /// <summary>
 2         /// 对中国人的问候
 3         /// </summary>
 4         /// <param name="Name"></param>
 5         public void SayHIChinese(string name)
 6         {
 7             Console.WriteLine("开始问候"); //增加日志
 8             Console.WriteLine("你好,{0}", name);
 9             Console.WriteLine("问候结束");//增加日志
10         }
11 
12         /// <summary>
13         /// 对美国人的问候
14         /// </summary>
15         /// <param name="name"></param>
16         public void SayHIAmerican(string name)
17         {
18             Console.WriteLine("开始问候"); //增加日志
19             Console.WriteLine("Hello,{0}", name);
20             Console.WriteLine("问候结束");//增加日志
21         }
22 
23         /// <summary>
24         /// 对日本人的问候
25         /// </summary>
26         /// <param name="name"></param>
27         public void SayHIJapanese(string name)
28         {
29             Console.WriteLine("开始问候"); //增加日志
30             Console.WriteLine("&*%$%^%$^,{0}", name);
31             Console.WriteLine("问候结束");//增加日志
32         }

  这样做显然太麻烦,每个方法都要去添加公共逻辑(增加日志)。所以要有一个公有方法添加日志。那我们又回到最初的方法。

 1 /// <summary>
 2         /// 对多国家的人进行问候
 3         /// </summary>
 4         public void SayHI(string Name,PeopleType peropleType)
 5         {
 6             Console.WriteLine("开始问候"); //增加日志
 7             if (peropleType == PeopleType.Chinese)
 8             {
 9                 Console.WriteLine("你好,{0}", Name);
10             }
11             else if (peropleType == PeopleType.American)
12             {
13                 Console.WriteLine("Hello,{0}", Name);
14             }
15             else if (peropleType == PeopleType.Japanese)
16             {
17                 Console.WriteLine("&*%$%^%$^,{0}", Name);
18             }
19             Console.WriteLine("问候结束");//增加日志
20         }

  以上方法可以增加公有逻辑,但是是存在分支。把方法分开写,不存在分支,但是每个方法里面要增加公有逻辑,那我们有什么办法把这两种合并在一起呢。有的,引入委托解决这一问题。代码如下:

 /// <summary>
        /// 完美方法:
        ///  1,方便增加公有逻辑
        ///  2,不因逻辑而变化
        ///  直接传入逻辑(方法)
        /// </summary>
        public void SayHIPerfect(string name,SayHIDelegete sayHiDelegete)
        {
            Console.WriteLine("开始问候"); //增加日志
            sayHiDelegete.Invoke(name);
            Console.WriteLine("问候结束");//增加日志
        }
/// <summary>
        /// 对中国人的问候
        /// </summary>
        /// <param name="Name"></param>
        public void SayHIChinese(string name)
        {
            Console.WriteLine("你好,{0}", name);
        }

        /// <summary>
        /// 对美国人的问候
        /// </summary>
        /// <param name="name"></param>
        public void SayHIAmerican(string name)
        {
            Console.WriteLine("Hello,{0}", name);
        }

        /// <summary>
        /// 对日本人的问候
        /// </summary>
        /// <param name="name"></param>
        public void SayHIJapanese(string name)
        {
            Console.WriteLine("&*%$%^%$^,{0}", name);
        }


 Console.WriteLine("-----------完美版本---------");
            {
                People p = new People();
                {
                    SayHIDelegete method = new SayHIDelegete(p.SayHIChinese);
                    p.SayHIPerfect("林青霞",method);
                }
                {
                    SayHIDelegete method = new SayHIDelegete(p.SayHIAmerican);
                    p.SayHIPerfect("Lilei", method);
                }
                {
                    SayHIDelegete method = new SayHIDelegete(p.SayHIJapanese);
                    p.SayHIPerfect("山本一夫", method);
                }
            }

总结

   委托的作用

            1.解藕,将系统 里面的公共逻辑和业务逻辑分开。

           2.除本文中讲到的解藕,委托还用于事件,观察者模式,lamada表达式,异步多线程等等,可以说委托在我们的编程中无处不在。

            

 

posted @ 2017-05-17 18:12  一叶青城  阅读(838)  评论(0编辑  收藏  举报