在"实现观察者模式(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. RPM Database

    RPM Database RPM 不仅在安装.升级.卸载方面工作出色,而且在查询和验证方面也表现非凡.你很久前安装了一个数据库软件,但现在忘记了它的版本号,也不知道它的说明文档的位置,可以通过 RPM ...

  2. 在内部局域网内搭建HTTPs

    在内部局域网内搭建HTTPs 配置环境 Windows版本:Windows Server 2008 R2 Standard Service Pack 1 系统类型:       64 位操作系统 内存 ...

  3. ansible源码解读

    Ansible源码获取 Ansible Github:https://github.com/ansible Ansible目录结构 $ tree -L 2 ansible-2.0.0.0 ansibl ...

  4. 记一些使用PyQt的问题

    本文自用,日常记录,不断更新 环境 1.使用 PyCharm IDE 2.PyQt5 3. 扩展配置 PyUIC转换后的代码处理 PyUIC 用于 将 QtDesigner 生成的 .ui 文件转换为 ...

  5. 采用MiniProfiler监控EF与.NET MVC项目(Entity Framework 延伸系列1)(转)

    前言 Entity Framework 延伸系列目录 今天来说说EF与MVC项目的性能检测和监控 首先,先介绍一下今天我们使用的工具吧. MiniProfiler~ 这个东西的介绍如下: MVC Mi ...

  6. Java编程的逻辑 (62) - 神奇的序列化

    本系列文章经补充和完善,已修订整理成书<Java编程的逻辑>,由机械工业出版社华章分社出版,于2018年1月上市热销,读者好评如潮!各大网店和书店有售,欢迎购买,京东自营链接:http:/ ...

  7. .NetCore生产环境下构建Consul(单个DC数据中心)的服务器健康检查

    下载最新的consul程序 consul 启动方式有两种 server 和client 默认是client 如果你不需要记录数据可以用 consul agent -dev 来启动 consul age ...

  8. STM32 串口通信使用奇偶校验

    STM32串口通信如果使用奇偶校验,需要设置数据位长度为9bit USART_InitStructure.USART_BaudRate = 9600; USART_InitStructure.USAR ...

  9. linux文本编码格式转化 字幕处理

    在处理字幕的时候,linux的编码格式转换很烦. 步骤: 用python先判断 其编码,再用iconv 转编码,再用awk处理格式. file不能判断吗?file有时不准. 1.python判断编码 ...

  10. thinkphp5.0未定义变量模板中提示错误

    在用tp5.0做一个项目网站,公共头需要用到一个变量,但这个变量又不想挨着定义,然后,刷新前台的时候就给提示,未定义变量. 直接放解决方案: 在config.php文件顶部添加: error_repo ...