在实际项目中使用观察者模式 前篇——委托和事件

我们公司面试初级C#的笔试题有一道题目:“请用代码实现:狗叫,主人被惊醒,猫跑了”。

这是一道很典型的可以使用观察者模式来解答的题目,可惜来做题的伙伴经常没有答上,今天我就从这道小题目开始,由浅到深讲讲观察者模式。

但是在讲观察者模式之前我们先要了解委托和事件。

 

委托和事件

委托(delegate)本质上是函数指针(在js里是函数变量的引用,js里并不需要声明delegate)。通俗来理解就是把一件事交给别人去做。

在代码里,“事情”就是functioin或method。delegate的作用就是把functioin或method装起来,不在new的地方执行,而在别的地方执行。

delegate需要把要执行的method注册进去,即告诉被委托人你要委托给他的事。

知道了委托,我们可以先试试水,用它来实现最开始说的笔试题的第一版。这里大家先不用去想为什么要这样做。

首先定义三位演员和他们要做的事:

    public class Dog
    {
        public void Bark()
        {
            Console.WriteLine("狗:汪汪汪");
        }
    }

    public class Master
    {
        public void WakeUp()
        {
            Console.WriteLine("主人:醒来");
        }
    }

    public class Cat
    {
        public void Run()
        {
            Console.WriteLine("猫:跑了");
        }
    }

其次,我们把三位演员new出来,并把他们要做的事放入委托,最后通过“中介人”来执行委托:

        public delegate void TheTestDelegate();
        //定义一个中间人来执行委托,需要接收一个委托参数
        private static void Agent(TheTestDelegate doSomething) {
            doSomething();
        }

        static void Main(string[] args)
        {
            Dog dog = new Dog();
            Master master = new Master();
            Cat cat = new Cat();
            TheTestDelegate testDelegate;
            //注册要委托的事
            testDelegate = dog.Bark;
            testDelegate += master.WakeUp;
            testDelegate += cat.Run;
            //执行委托
            Agent(testDelegate);
        }

这样一来,中间人就把我们刚刚委托给他的事都给办了

这样写的好处是显而易见的。委托将Main和各位演员的操作隔离了。每次执行委托时,我并不需要知道各位演员即将要做什么骚操作(比如狗突然喵喵叫)。从而达到了解耦的效果。

 

知道了什么是委托和委托怎么用之后,接下来我们看看什么是事件:

事件(event)是一种封装了的委托,他做了什么封装,为什么要这么封装呢?我们来继续研究上面的例子。

在上面的代码里,委托被定义成了公共的变量。这样就意味着谁都可以修改,那显然不行。

所以我们要让中介人自己管理他的委托合同。只有雇佣(new)他的人,才可以委托他干活。而作为发布人的我们仅需要发布委托和触发执行事件。

首先我们把Agent单独建一个class,但是我们要怎么让中介人自己管理委托呢?即使把delegate移到Agent里,如果将delegate声明为public,那照样谁都可以赋值。若声明为private,则谁都委托不了。

这时我们可以试试看用事件:

    //定义委托
    public delegate void TheTestDelegate();

    public class Agent
    {
        //声明事件
        public event TheTestDelegate theEvent;

        public void DoDelegate()
        {
            theEvent();
        }
    }

        static void Main(string[] args)
        {
            Agent agent = new Agent();
            //注册要委托的事
            agent.theEvent += new Dog().Bark;//注意,这里第一次不需要也不能用=号了
            agent.theEvent += new Master().WakeUp;
            agent.theEvent += new Cat().Run;
            //触发事件
            agent.DoDelegate();
        }

大家可能觉得有疑问:这不还是用了public吗?

其实不然,为什么这里把method注册进事件不需要也不能使用“=”号了呢?

其实声明事件类似于把委托声明成了属性 (Property)。我们的+=和-=相当于访问了set访问器,而真正的delegate其实被声明成了private。

 

好了,搞了这么久,前戏终于做完了。接下来可以开始说说观察者模式了。

 

posted @ 2019-07-20 21:20  Weisskunig  阅读(406)  评论(0编辑  收藏  举报