深入理解回调 CallBack

2017-02-17  本文已影响437人  道阻且长_行则将至

相信大家都知道委托和事件,没错,委托和事件是用来传递和保存函数用的,那么 回调 呢,近段时间的学习中经常碰到 回调,通过查阅相关资料,我发现回调对理解委托是很重要的。简单的说,回调就是把方法当参数传到另外一个方法里面,传的过程中会用到委托,而回调的使用能抽离一个函数中不同的部分,使程序变得更加简洁和灵活。

举个例子:

假设我需要你帮我做一件事情,我有两个选择:

1. 把这个事情交给你,然后一直等到你做完这个事
2. 把这个事情交给你,然后继续去做我的事,等你做完了后,你通知我下你做的结果

好了,明白了callback,现在自然的思路就是:我是A, B委托让我在我这边的某事件发生后callback他,好的,到时个我A这边事件发生了,我就直接调用B指定的那个函数,callback完毕!要注意这个事件发生的次序,B委托A,然后A中的事件发生,然后A调用了B的函数。有三个部分组成!

但是这种设计方式是不好的!问题出在A直接call了委托者。这时假如要增加一个需要通知的对象,那就要改变A对象的内容,再增加一个,再改变。同样,当一个对象需要减除接受这个通知时,又要改变A对象的内容,要在A对象中维护这个需求,实在是不爽,因为对A来说,跟其它对象的耦合度太高了。那怎么办呢?

引入一个第三方对象X,它维护一个需要通知的列表,任何对象需要得到通知的时候,就告诉X而不是去直接委托A。而做为A,本身不需要关心要通知到哪些对象,只需要告诉X,事件发生了。该通知哪些对象是你X的事。但你会问,那这样不是把维护通知者列表的复杂性转移到C对象上去了么?并且还好端端多出一个对象来,岂不是把事情搞得更复杂了?并不是的,这儿其实就相当于把一个复杂易变的功能从A中剥离出来,A只负责做好他的更重要的工作,关注于事件本身,而不需要关注事件发生了,要通知哪些对象。这样,确实是降低了整个系统的耦合度。并且有时候会有一种情况:想接受到通知的某个对象,并不想让A知道他侦听了这个事件!!!这时候,更是需要第三方对象X的存在。

这时候我就大致明白 callback 以及如何实现一个设计良好的 callback 了,然后,callback与委托又有什么关系呢?委托就是用来方便地实现callback的手段!!!

这时我们考虑这样一个模拟情景,涉及到两个对象,一个员工,一个Leader在做一个项目,项目一开始时Leader就告诉员工,每当员工的完成一个TASK的时候,就要向LEADER报告,由LEADER来REVIEW并更新WBS。这是一个典型的callback事件。根据我们前面的考量,我们知道,不能由员工直接通知Leader,这是不好的设计,比如说:某天忽然Manager心血来潮,想密切关注该项目的进度,但他又不想让员工知道这个,怕给员工增加压力。(真是好领导呀~~~)。所以,我们买了一个机器人,当员工每完成一个TASK,员工就踢机器人一脚,机器人就会跑去通知Leader。当经理需要关注进度时,就给机器人下指令,员工踢你时你也要告诉我。这样,问题就都解决了。设计如下:

代码1
using System;
 using System.Collections.Generic;
 using System.Linq;
 using System.Text;

 namespace DelegateTest1
{
    //职员类
    class Employee
    {   
        //踢机器人 完成工作
        public void KickRobot(Robot r)
        {
            Console.WriteLine("I have finished a task!");
            r.NoticeOthers();
        }
    }
    
    //领导类
    class Leader
    {
        //领导的反应
        public void AcceptNotice()
        {
            Console.WriteLine("Yes,i will check it!");
        }
    }
    
    //经理类  
    class Manager
    {
        //经理的反应
        public void AcceptNotice()
        {
            Console.WriteLine("UMM,good boy!");
        }
    }
    
    //机器人类
    class Robot
    {
        //通知列表
        private List<object> NoticeList=new List<object>();
        //通知列表所有人
        public void NoticeOthers()
        {
            foreach (object s in NoticeList)
            {
                if (s is Leader)
                {
                    ((Leader)s).AcceptNotice();                 
                }
                if (s is Manager)
                {
                    ((Manager)s).AcceptNotice();
                }
            }
        }
        //添加进列表
        public void AddToList(object a)
        {
            NoticeList.Add(a);
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Employee XiaoLi = new Employee();
            Leader LaoLiu = new Leader();
            Manager AnZong = new Manager();
            Robot WillSmith = new Robot();

            WillSmith.AddToList(LaoLiu);//Only leader LaoLiu want to know that.        
             XiaoLi.KickRobot(WillSmith);

            Console.WriteLine(" ");

            WillSmith.AddToList(AnZong);//The Manger suddenly want to know that too.
             XiaoLi.KickRobot(WillSmith);
        }
    }
}

仔细考虑上面的代码,我们“买”了一个Robot,花费了额外的“代价”,并且,这一流程有点绕弯子,是否可以直接在员工类中开放一个接口,需要监听者直接往这个接口里面放函数,到时我做了就OK。这时候,委托就派上用场了,如下:

代码2
using System;
 using System.Collections.Generic;
 using System.Linq;
 using System.Text;

 namespace DelegateTest2
{
    //雇员类
    class Employee
    {
        //定义通知目标的委托
        public delegate void NoticeTarget(string msg);
        //实例化这个委托
        private NoticeTarget NoticeList;
        //注册委托函数  这里用到了回掉
        public void AddToNoticeList(NoticeTarget ExternalMethod)
        {
            NoticeList += ExternalMethod;
        }
        //完成工作了
        public void Notice()
        {
            if (NoticeList != null)
            {
                NoticeList("I have finished a task!");   //回调
            }
        }
    }

    class Leader
    {
        public void AcceptNotice(string msg)
        {
            Console.WriteLine(msg+" Yes,i will check it!");
        }
    }

    class Manager
    {
        public void AcceptNotice(string msg)
        {
            Console.WriteLine(msg+" UMM,good boy!");
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Employee XiaoLi = new Employee();
            Leader LaoLiu = new Leader();
            Manager AnZong = new Manager();
            //注册领导和经理的反应函数
            XiaoLi.AddToNoticeList(LaoLiu.AcceptNotice);
            XiaoLi.AddToNoticeList(AnZong.AcceptNotice);
            //这里实现了回调
            XiaoLi.Notice();
        }
    }
}
上一篇下一篇

猜你喜欢

热点阅读