美文网首页
深入理解回调 CallBack

深入理解回调 CallBack

作者: 道阻且长_行则将至 | 来源:发表于2017-02-17 10:40 被阅读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();
            }
        }
    }
    

    相关文章

      网友评论

          本文标题:深入理解回调 CallBack

          本文链接:https://www.haomeiwen.com/subject/cuxbittx.html