当前位置: 首页 > news >正文

C#-设计模式-观察者模式

1.定义

观察者模式说白了就是事件;之前没有观察者模式的时候,当我们需要考察属性的状态然后作出相应的处理,我们只能当状态满足的时候去调用方法。

不过这样就造成了事件处理和事件绑定在了一起,一旦我们要添加其他的处理功能,就不得不修改原有的检测代码,对于修改并不友好。

 

2.观察者模式的发展

2.1 一个简单的需求

对于一个简单的流程比如说,检测谁有没有烧开,以前没有事件的时候,如果我们就需要写如下代码;

public class BoilWater
{
    public int waterTemperature = 0;

    public void Boil()
    {
        for (int i = 0; i < 100; i++)
        {
            waterTemperature = i;
            Thread.Sleep(100);
            if (waterTemperature == 100)
            {
                Call();
            }
        }
    }

    public void Call()
    {
        Console.Write("The Water is Boiled!");
    }
}

如上就是检测看,谁有没有烧开,如果水烧开了(到达100C),就调用通知方法(Call);

但是上面的代码缺点也很明显,那就是:一旦我们要增加水烧开后的处理程序,我们就不得不修改Boil方法;

那有没有办法可以让我们不修改代码的情况下,在运行中动态的去修改水烧开时的处理程序呢?答案是肯定的,那就是使用观察者模式;

2.2 观察者模式

public class BoilWater
{
    public int waterTemperature = 0;

    public IList<RunInter> Observers = new List<RunInter>();

    public void Boil()
    {
        for (int i = 0; i < 100; i++)
        {
            waterTemperature = i;
            Thread.Sleep(100);
            if (waterTemperature == 100)
            {
                CallAllObserve();
            }
        }
    }

    public void CallAllObserve()
    {
        foreach (var item in Observers)
        {
            item.Run();
        }
    }

    public void AddObserver(RunInter runner)
    {
        Observers.Add(runner);
    }

    public void RemoveObserver(RunInter runner)
    {
        Observers.Remove(runner);
    }
}

    public interface RunInter
    {
        void Run();
    }

    public class Call : RunInter
    {
        public void Run()
        {
            Console.Write("The Water is Boiled!");
        }
    }

    public class DoOtherThing : RunInter
    {
        public void Run()
        {
            Console.Write("Do Other Things");
        }
    }

这里我们在被观察的类中放一个存储接口的列表,然后在事件满足的时候,将列表中的每一个接口都执行一遍,而且因为有AddObserver和RemoveObserver方法,因此在程序运行的过程中我们也可以动态的添加新的处理代码,或删除已有的处理代码。

但是这样做确实是有一点繁琐,要定义接口,还要再检测类中加上对应的列表,还好.NET已经为我们设计了完美的替代方案,那就是使用委托和事件;

2.3 使用委托和事件来实现观察者模式

public class BoilWater
{
    public int waterTemperature = 0;

    private event Action actions;

    public void Boil()
    {
        for (int i = 0; i < 100; i++)
        {
            waterTemperature = i;
            Thread.Sleep(100);
            if (waterTemperature == 100)
            {
                actions();
            }
        }
    }

    public void AddObserver(Action runner)
    {
        actions += runner;
    }

    public void RemoveObserver(Action runner)
    {
        actions -= runner;
    }
}

调用的时候只需要:

var boilWater = new BoilWater();
boilWater.AddObserver(() =>
{
    Console.WriteLine("Water is Boiled");
});
boilWater.AddObserver(() =>
{
    Console.WriteLine("Do Other Things");
});

这样当水开的时候,两个控制台打印的方法,都会被执行了。

其实在这里的Action就是.Net自带的委托对象,其实委托我们在和上面的代码对比后,就可以认为他是一系列相似方法的集合列表,当执行委托之后,这个集合中的每一个方法就会依次被执行(有先后顺序,并不是并发执行);

但这种方式就为我们实现观察者模式的逻辑提供的很大的方便。

2.4 委托和事件的区别

2.3中的代码我使用了event关键字,就是讲委托声明为事件了,很多人区分不出委托和事件的区别,其实很简单,事件是一种特殊的委托;

既然是委托,其实说到底他还是方法的集合,当执行事件后,这个集合中的所有方法都会被执行;

区别在于,委托可以在委托所属的类外面进行添加和删除操作;但是事件不行,事件只能在事件所属的类内部进行添加和删除操作。

 

3.特点

优点:将事件的发生和事件的处理分离开,并且可以动态的添加和删除处理方法

缺点:处理方法中如果有互相引用的情况,就会引起系统崩溃,而且解耦的手法影响了代码的执行效率(所有的设计模式几乎都有该缺点)

希望各位学习愉快;

转载于:https://www.cnblogs.com/gamov/p/10523310.html

相关文章:

  • Java基础内部类、包的声名、访问修饰符、代码块整理
  • c/c++ 网络编程 read,write函数深入理解
  • DevExpress WinForms使用教程:SVG图库和Image Picker
  • 4.标准信号与槽
  • 爬取碧蓝航线wiki
  • LeetCode 第104题 二叉树的最大深度
  • 学习进度二
  • Maven 属性
  • ASP.NET Core 基于JWT的认证(二)
  • javascript面向对象编程,带你认识封装、继承和多态
  • 【SQL优化】MySQL官网中可优化的层次结构
  • 1.2变量
  • Kubernetes 笔记 06 豌豆荚之旅(一)
  • 2019.3.19
  • JPA将查询结果转换为DTO对象
  • JS 中的深拷贝与浅拷贝
  • 【面试系列】之二:关于js原型
  • JavaScript中的对象个人分享
  • Java程序员幽默爆笑锦集
  • java正则表式的使用
  • js继承的实现方法
  • JS数组方法汇总
  • 编写符合Python风格的对象
  • 从 Android Sample ApiDemos 中学习 android.animation API 的用法
  • 从零开始的webpack生活-0x009:FilesLoader装载文件
  • 服务器之间,相同帐号,实现免密钥登录
  • 关于 Linux 进程的 UID、EUID、GID 和 EGID
  • 关于Java中分层中遇到的一些问题
  • 王永庆:技术创新改变教育未来
  • 异步
  • 中国人寿如何基于容器搭建金融PaaS云平台
  • MPAndroidChart 教程:Y轴 YAxis
  • 湖北分布式智能数据采集方法有哪些?
  • 基于django的视频点播网站开发-step3-注册登录功能 ...
  • ​queue --- 一个同步的队列类​
  • ​软考-高级-系统架构设计师教程(清华第2版)【第9章 软件可靠性基础知识(P320~344)-思维导图】​
  • (31)对象的克隆
  • (6)STL算法之转换
  • (Repost) Getting Genode with TrustZone on the i.MX
  • (草履虫都可以看懂的)PyQt子窗口向主窗口传递参数,主窗口接收子窗口信号、参数。
  • (剑指Offer)面试题41:和为s的连续正数序列
  • (力扣记录)235. 二叉搜索树的最近公共祖先
  • (企业 / 公司项目)前端使用pingyin-pro将汉字转成拼音
  • (转)ABI是什么
  • *ST京蓝入股力合节能 着力绿色智慧城市服务
  • ./indexer: error while loading shared libraries: libmysqlclient.so.18: cannot open shared object fil
  • .NET Core引入性能分析引导优化
  • .net mvc 获取url中controller和action
  • .net 微服务 服务保护 自动重试 Polly
  • .net6解除文件上传限制。Multipart body length limit 16384 exceeded
  • .NET建议使用的大小写命名原则
  • .NET应用架构设计:原则、模式与实践 目录预览
  • .Net语言中的StringBuilder:入门到精通
  • .Net中间语言BeforeFieldInit
  • .sh