在"实现观察者模式(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. Nginx报错:upstream timed out (110: Connection timed out)和client intended to send too large body【转】

    nginx日志报错 2018/01/26 16:36:49 [error] 23327#0: *54953 upstream timed out (110: Connection timed out) ...

  2. LCT摘要

    介绍.用途 LCT是树链剖分中的一种,又叫实链剖分.动态树,常用于维护动态的树.森林. 维护方式 LCT并不直接维护原树,而是用一堆splay作为辅助树来维护.原树中的一条实链上的点在一棵splay中 ...

  3. MVC5使用EF6 Code First--创建EF数据模型(一)

    此Web应用程序演示如何使用Entity Framework 6和Visual Studio 2015创建ASP.NET MVC 5应用程序.本教程使用“Code First ”即代码先行.有关如何在 ...

  4. Python学习笔记:算法的重要性

    今日看了一个基础的教程<8分钟学会一个算法>,偶然间看到一个很简单的例子,仅当记录一下. 题目:已知a+b+c=1000,且a^2+b^2=c^2,求a,b,c的所有自然数解? #### ...

  5. Django Celery定时任务和时间设置

    1.Celery加入定时任务 Celery除了可以异步执行任务之外,还可以定时执行任务.在实例代码的基础上写个测试方法: #coding:utf- from celery.task.schedules ...

  6. android studio 3.0之后版本自定义文件名生成apk文件

    修改app模块的build.gradle 在android闭包中添加以下代码 //指定打包后应用名称 android.applicationVariants.all { variant -> v ...

  7. Atom组件

    Atom组件 最近用Atom写博客比较多,然后发现一个很严重的问题.. 没有一个我想要的上传图片的方式,比如某乎上边就可以直接copy/paste文件,然后进行上传. 然而在Atom上没有找到类似的插 ...

  8. 【BZOJ】2120: 数颜色

    题解 练习一下带修改莫队 先按照左端点的块排序,再按照右端点的块排序,然后按照时间排序 每个修改操作存一下修改前这个位置的值就可以逆序操作了 代码 #include <bits/stdc++.h ...

  9. Codeforces 348B - Apple Tree

    348B - Apple Tree 我们设最后答案为 x , 我们我们就能用x表示出所有节点下面的苹果个数, 然后用叶子节点求lcm, 取最大的可行解. #include<bits/stdc++ ...

  10. 035 spark与hive的集成

    一:介绍 1.在spark编译时支持hive 2.默认的db 当Spark在编译的时候给定了hive的支持参数,但是没有配置和hive的集成,此时默认使用hive自带的元数据管理:Derby数据库. ...