C#观察者模式应用

目录

一、什么是观察者模式

二、C#中观察者模式的实现

三、两种实现的用法

1、事件与委托

2、IObserver和IObservable

四、参考文献


一、什么是观察者模式

观察者(Observer)模式的定义:指多个对象间存在一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。这种模式有时又称作发布-订阅模式(Publish-Subscribe)、模型-视图(Model-View)模式、源监听器(Source-Listener)或者从属者模式,它是对象行为型模式。

  • 模型(Model) -发布者是数据源,模型层, 程序员编写程序应有的功能(实现算法等等)、数据库专家进行数据管理和数据库设计(可以实现具体的功能)。
  • 视图(View) -监听者是视图层, 界面设计人员进行图形界面设计。

观察者模式是一种对象行为型模式,其主要优点如下。

  1. 降低了目标与观察者之间的耦合关系,两者之间是抽象耦合关系。符合依赖倒置原则。
  2. 目标与观察者之间建立了一套触发机制。

它的主要缺点如下。

  1. 目标与观察者之间的依赖关系并没有完全解除,而且有可能出现循环引用。
  2. 当观察者对象很多时,通知的发布会花费很多时间,影响程序的效率。

二、C#中观察者模式的实现

C#语言,其事件和委托本身就是观察者模式的基本实现。除此之外,属性修改通知以及属性依赖等也是观察者模式的用途之一,在WinForm或者WPF中,通常将集合类控件,绑定到集合上,当集合数据发生变化时,绑定的控件能够得到通知,并且能够自动刷新界面。

    在C#中使用观察者模式,除了常用的event事件之外,还可以通过IObservable<T>和IObserver<T>两个接口来实现事件流模式,看起来有些复杂,但是这种方式有很多优点,并且很容易能跟Reactive Extensions框架配合。最后讲述了Observerable集合BindingList<T>和ObservableCollection<T>,他们不是线程安全的,使用的时候需要注意多线程读写的问题,这两个集合通常跟配套的支持集合的控件来绑定使用,这样能做到当集合数据发生变化时,对应的界面能够自动刷新。

在软件世界也是这样,例如,Excel 中的数据与折线图、饼状图、柱状图之间的关系;MVC 模式中的模型与视图的关系;事件模型中的事件源与事件处理者。所有这些,如果用观察者模式来实现就非常方便。

C#的设计者通过关键字event来简化对观察者模式的使用。它的基本用法是,首先使用event关键字定义事件,然后注册事件回调方法EventHandler,回调方法通常包含两个参数,一个object类型的sender和一个继承自EventArgs的参数,该参数携带一些触发事件的必要信息。

三、两种实现的用法

1、事件与委托

    event事件其实是对委托的包装。对event的包装成为EventHandler,有泛型和非泛型版本,泛型主要是继承自EventArgs的类型。具体使用可以了解如何使用event定义事件。并且由此了解Action Func的用法,加深对委托的理解。

2、IObserver<T>和IObservable<T>

  如果将一个List<T>绑定到WinForm或者WPF中的ListBox,当List发送改变的时候,UI不会更新,这是因为List<T>并不支持Observer模式。当然如果单个对象发生改变,但整个List并没有事件能够向外通知其内容发送了改变。诚然我们可以对List进行包装,在Add或者Remove方法里添加事件通知,可以但没必要,在WinForm和WPF中都有Observable集合,他们分别是BindingList<T>和ObservableCollection<T>。

    这两个集合类型表现起来就跟Collection<T>一样,但是他提供了额外的通知。比如,对于UI组件,当绑定的集合发送改变时,UI会自动进行更新。ObservableCollection<T>实现了INotifyCollectionChanged接口,所以他有CollectionChanged事件。这个时间会告知集合发生了什么改变,并且会提供旧的和新的元素,以及旧的和新的元素在集合中的位置,换句话说,根据事件我们能够正确的重新绘制ListBox或者其他集合组件。

    需要注意的是BindingList<T>和ObservableCollection<T>都不是线程安全的集合,因此在多线程读写集合的时候,需要特别注意。一种方式是继承自Observable集合,然后对一些写入操作加锁。另外一种方法是继承自ConcurrentBag<T>,然后实现INotifyCollectionChanged接口。相对而言,第一种方式简单一些。

IObservable<T>和IObserver<T> 类型的代码

Weather weather = new Weather() {  Teapreture=new WeatherData { temperature="25度"} };
Person wanglin = new Person() { Name="王玲"};
Person mulan = new Person() { Name = "木兰" };
weather.Subscribe(wanglin);///Subscribe 等同于 事件的"+"
weather.Subscribe(mulan);//
weather.NotifyTeapreture();//公告温度
Console.Read();
/// <summary>
/// 订阅者
/// </summary>
public class Person : IObserver<WeatherData>
{//关注温度
    public string Name { get; set; }
    public void OnCompleted()
    {
        Console.WriteLine(" ");
    }

    public void OnError(Exception error)
    {
        throw new NotImplementedException();
    }

    public void OnNext(WeatherData value)
    {
        Console.WriteLine($"我{Name}知道今天的天气了,是{value.temperature}");

    }
}
/// <summary>
/// 数据
/// </summary>
public class WeatherData
{
    /// <summary>
    /// 气温
    /// </summary>
    public string temperature { get; set; }
    /// <summary>
    /// 湿度
    /// </summary>
    public string humility { get; set; }
    /// <summary>
    /// 气压
    /// </summary>
    public string pressure { get; set; }
}
/// <summary>
/// 发布者
/// </summary>
public class Weather : IObservable<WeatherData>
{
    //提供温度 数据
    public WeatherData Teapreture { get; set; }
    private List<IObserver<WeatherData>> subsribers = new List<IObserver<WeatherData>>();
    public IDisposable Subscribe(IObserver<WeatherData> observer)
    {
        if (!subsribers.Contains(observer))
        {
            subsribers.Add(observer);

        }
        return new UnSubsribe(this, observer);
    }
    class UnSubsribe : IDisposable
    {
        private Weather weather;
        private IObserver<WeatherData> observer;

        public UnSubsribe(Weather weather, IObserver<WeatherData> observer)
        {
            this.weather = weather;
            this.observer = observer;
        }

        public void Dispose()
        {
            weather.subsribers.Remove(observer);
        }
    }
    public void NotifyTeapreture()
    {
        foreach (var item in subsribers)
        {
            item.OnNext(Teapreture);
        }
    }
    public void OnComplete()
    {
        foreach (var item in subsribers)
        {
            item.OnCompleted();
        }
    }

}

四、参考文献

【C# 设计模式】观察者模式 - 小林野夫 - 博客园 (cnblogs.com)

相关推荐

  1. C# 观察模式

    2024-06-15 12:56:06       26 阅读
  2. [C/C++] -- 观察模式

    2024-06-15 12:56:06       12 阅读
  3. c#观察设计模式

    2024-06-15 12:56:06       34 阅读
  4. C++ 设计模式观察模式

    2024-06-15 12:56:06       29 阅读
  5. C++ 设计模式观察模式

    2024-06-15 12:56:06       21 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-06-15 12:56:06       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-06-15 12:56:06       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-06-15 12:56:06       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-06-15 12:56:06       20 阅读

热门阅读

  1. Qt正则表达式

    2024-06-15 12:56:06       7 阅读
  2. HTML DOM 事件

    2024-06-15 12:56:06       7 阅读
  3. SpringBoot 项目,三种方式实现打印 sql 日志

    2024-06-15 12:56:06       10 阅读
  4. Redis作为缓存

    2024-06-15 12:56:06       9 阅读
  5. Python+Opencv是实现车牌自动识别

    2024-06-15 12:56:06       6 阅读
  6. 面试问题-除了threading还会哪种并发

    2024-06-15 12:56:06       7 阅读
  7. 媒体查询的屏幕尺寸范围

    2024-06-15 12:56:06       7 阅读
  8. LeetCode 7题:整数翻转(原创)

    2024-06-15 12:56:06       8 阅读
  9. 使用静态方法接受对象参数

    2024-06-15 12:56:06       9 阅读