深入理解回调 CallBack

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

举个例子:

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

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();
        }
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,204评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,091评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,548评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,657评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,689评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,554评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,302评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,216评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,661评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,851评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,977评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,697评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,306评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,898评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,019评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,138评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,927评论 2 355

推荐阅读更多精彩内容