在"实现观察者模式(Observer Pattern)的2种方式"中,曾经通过接口的方式、委托与事件的方式实现过观察者模式。本篇体验使用Action实现此模式,并从中体验委托与事件的区别。

□ 使用Action实现观察者模式

就举一个足球场上的例子,当裁判吹响终场哨,胜队庆祝,失败队落寞。把裁判看作是被观察者,比赛中的两队看作是观察者。

裁判作为被观察者需要提供一个Action委托供观察者方法注册。

    public class Referee
    {
        public Action DoSth;

        public void ISayGameOver()
        {
            Console.WriteLine("嘀嘀嘀......比赛结束了~~");
            DoSth();
        }
    }

胜利的队和失败的队拥有共同的基类。

    public class Team
    {
        private string _name;

        public Team(string name)
        {
            _name = name;
        }

        public string Name
        {
            get { return _name; }
        }
    }

胜利队或失败队,作为观察者,必须有符合Referee中Action定义的方法。

    public class WinTeam : Team
    {
        public WinTeam(string name) : base(name){}

        public void Celebrate()
        {
            Console.WriteLine("我们晋级了,好开心!");
        }
    }

    public class LoseTeam : Team
    {
        public LoseTeam(string name) : base(name){}

        public void WeAreSad()
        {
            Console.WriteLine("比赛输了,好伤心!");
        }
    }


客户端,先把失败队和胜利队的方法注册到Action变量,然后由被观察者的一个方法触发委托链和方法。

        static void Main(string[] args)
        {
            Referee referee = new Referee();
            var winTeam = new WinTeam("胜利队");
            var loseTeam = new LoseTeam("失败队");

            //注册观察者
            referee.DoSth += winTeam.Celebrate;
            referee.DoSth += loseTeam.WeAreSad;

            //被观察者启动事件通知观察者
            referee.ISayGameOver();
        }

□ 体验委托与事件的区别

现在,我们在客户端,在调用Referee的实例方法ISayGameOver之前,尝试把Referee的委托变量DoSth设置为null。

        static void Main(string[] args)
        {
            Referee referee = new Referee();
            var winTeam = new WinTeam("胜利队");
            var loseTeam = new LoseTeam("失败队");

            //注册观察者
            referee.DoSth += winTeam.Celebrate;
            referee.DoSth += loseTeam.WeAreSad;
            referee.DoSth = null;

            //被观察者启动事件通知观察者
            referee.ISayGameOver();
        }


可见,当把把Referee的委托变量DoSth设置为null后,所有注册的方法将得不到执行。

如果把Referee的委托变量DoSth修饰为事件。

    public class Referee
    {
        public event Action DoSth;

        public void ISayGameOver()
        {
            Console.WriteLine("嘀嘀嘀......比赛结束了~~");
            if (DoSth != null)
            {
                DoSth();
            }

        }
    }


可见,当把委托变量DoSth修饰为事件后,只能通过+=和-=注册、取消方法,不能通过=设置。

把referee.DoSth = null;注释掉,将不会报错。

“委托、Lambda表达式、事件系列”包括:

委托、Lambda表达式、事件系列01,委托是什么,委托的基本用法,委托的Method和Target属性

委托、Lambda表达式、事件系列02,什么时候该用委托

委托、Lambda表达式、事件系列03,从委托到Lamda表达式

委托、Lambda表达式、事件系列04,委托链是怎样形成的, 多播委托, 调用委托链方法,委托链异常处理

委托、Lambda表达式、事件系列05,Action委托与闭包

委托、Lambda表达式、事件系列06,使用Action实现观察者模式,体验委托和事件的区别

委托、Lambda表达式、事件系列07,使用EventHandler委托

委托、Lambda表达式、事件系列06,使用Action实现观察者模式,体验委托和事件的区别的更多相关文章

  1. 委托/lambda表达式/事件

    委托 委托是执行安全的类,它的使用方式与类类似(即都需要定义再实例化),不同在于,类在实例化之后叫对象或类的实例,但委托在实例化后仍叫委托,委托可以把函数作为参数传递. 语法声明: delegate ...

  2. 委托+内置委托方法+多播委托+lambda表达式+事件

    委托概念:如果我们要把方法当做参数来传递的话,就要用到委托.简单来说委托是一个类型,这个类型可以赋值一个方法的引用. 声明委托: 在C#中使用一个类分两个阶段,首选定义这个类,告诉编译器这个类由什么字 ...

  3. C#编程 委托 Lambda表达式和事件

    委托 如果我们要把方法当做参数来传递的话,就要用到委托.简单来说委托是一个类型,这个类型可以赋值一个方法的引用. 声明委托 在C#中使用一个类分两个阶段,首选定义这个类,告诉编译器这个类由什么字段和方 ...

  4. Unity C# 多态 委托 事件 匿名委托 Lambda表达式 观察者模式 .NET 框架中的委托和事件

    一.多态 里氏替换原则: 任何能用基类的地方,可以用子类代替,反过来不行.子类能够在基类的基础上增加新的行为.面向对象设计的基本原则之一. 开放封闭原则: 对扩展开放,意味着有新的需求或变化时,可以对 ...

  5. 委托 lambda表达式浅显理解

    方法不能跟变量一样当参数传递,怎么办,C#定义了委托,就可以把方法当变量一样传递了,为了简单,匿名方法传递,省得再声明方法了:再简单,lambda表达式传递,比匿名方法更直观. public dele ...

  6. C#学习笔记三(委托·lambda表达式和事件,字符串和正则表达式,集合,特殊的集合)

    委托和事件的区别 序号 区别 委托 事件 1 是否可以使用=来赋值 是 否 2 是否可以在类外部进行调用 是 否 3 是否是一个类型 是 否,事件修饰的是一个对象 public delegate vo ...

  7. 委托、Lambda表达式、事件系列05,Action委托与闭包

    来看使用Action委托的一个实例: static void Main(string[] args) { int i = 0; Action a = () => i++; a(); a(); C ...

  8. 委托、Lambda表达式、事件系列07,使用EventHandler委托

    谈到事件注册,EventHandler是最常用的. EventHandler是一个委托,接收2个形参.sender是指事件的发起者,e代表事件参数. □ 使用EventHandler实现猜拳游戏 使用 ...

  9. 委托、Lambda表达式、事件系列04,委托链是怎样形成的, 多播委托, 调用委托链方法,委托链异常处理

    委托是多播委托,我们可以通过"+="把多个方法赋给委托变量,这样就形成了一个委托链.本篇的话题包括:委托链是怎样形成的,如何调用委托链方法,以及委托链异常处理. □ 调用返回类型为 ...

随机推荐

  1. Mysql导入脚本失败,提示需要SUPER权限

    1.删除: /*!50013 DEFINER=`root`@`localhost` SQL SECURITY DEFINER */ 2.查看增删函数有没有重复 3.删除: set GLOBAL log ...

  2. 关于内核中spinlock的一些个人理解 【转】

    由于2.6内核可以抢占,应该在驱动程序中使用 preempt_disable() 和 preempt_enable(),从而保护代码段不被抢占(禁止 IRQ 同时也就隐式地禁止了抢占).preempt ...

  3. PHP 获取某年第几周的开始日期和结束日期的实例

    /** * 获取某年第几周的开始日期和结束日期 * @param int $year * @param int $week 第几周; */ public function weekday($year, ...

  4. .NetCore下B/S结构 初探基于遗传学算法的中学自动排课走班(二)

    分析下染色体基因 这里用 老师 课程 班级 教室 周天 上下晚 课时作为染色体编码我封装了如下类 /// <summary> /// NP 授课事件 由教室.课程.班级 时间片段构成 li ...

  5. #HTML 块级、内联、内联块级元素

    [常用的块级元素] div,form,p,table,h1~h6,hr,dl,ol,ul,pre等 [常用的内联元素] a,img,input,span,br,select,strong,em,tex ...

  6. net mvc中angular

    把angular项目整合到.net mvc中   之前的开发选择的是完全舍弃服务端,仅保留最简单web服务器提供angular经打包的静态资源,此外所有的业务与数据请求都访问一个分离的WebApi来实 ...

  7. 【AtCoder】AGC020

    A - Move and Win 题解 看两个人相遇的时候谁先手即可,相遇之后第一个移动的人必输 代码 #include <bits/stdc++.h> #define fi first ...

  8. 【AtCoder】ARC103

    C - //// 为了防止一些多余的判断,我选择直接记录每个数的个数,然后枚举第一个数,找第一个数之外第二个数改变最少的情况下应该选什么 代码 #include <bits/stdc++.h&g ...

  9. 使用SOCKET获取网页的内容

    使用fsockopen()函数来实现获取页面信息,完整代码如下 //设置字符集(由于要抓取的网易网站字符集编码是gbk编码) header("content-type:text/html;c ...

  10. Windows下PHP多线程扩展pthreads的安装

    pthreads扩展安装步骤 1.查看phpinfo() 获取PHP版本号及位数(x86表示32位,x64表示64位).编译器版本.PHP配置文件加载所在位置等.如下图所示: 2.pthreads扩展 ...