C#设计模式---观察者模式简单例子

简介: 版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq1010885678/article/details/38169159 在...
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq1010885678/article/details/38169159

在开发过程中经常遇到一个模块中的 一个方法调用了其他模块中相关的方法

比如说在一个系统中,如果出现了错误,就调用专门进行错误处理的模块中的方法进行错误处理

而因为错误处理的操作有很多,所以将这些具体的操作封装在其他的模块中

在专门进行错误处理的模块中调用其他模块中的错误操作方法

这样一来在主系统中只要实例化专门进行错误处理的模块对象

并调用其相关的方法,其他模块中的具体方法也都会被执行

这时专门进行错误处理的模块被称为发布者

其他拥有具体错误操作的模块称为订阅者

只要发布者一发布信息(方法被调用)

所有的订阅者都会相应(具体方法也会执行)


最直接的做法是在模块中引用并实例化其他模块的对象

然后调用其方法

下面给出一个简单的例子,用类来模拟模块

首先是具体的错误操作

在例子中有三个具体的错误操作

分别为:发送邮件,发出警报,窗口抖动

/// <summary>
    /// 具体的错误处理方式类(模块)1,此为订阅者
    /// </summary>
    public class Handle1
    {
        /// <summary>
        /// 出现错误时做出发送邮件的处理
        /// </summary>
        public void ErrorHanding()
        {
            Console.WriteLine("出现错误!发送了一封邮件到管理员!");
        }
    }
/// <summary>
    /// 具体的错误处理方式类(模块)2,此为订阅者
    /// </summary>
    public class Handle2
    {
        /// <summary>
        /// 出现错误时做出发出警报的处理
        /// </summary>
        public void ErrorHanding()
        {
            Console.WriteLine("出现错误!警报!!!!!!!!!!!!!!!!");
        }
    }

/// <summary>
    /// 具体的错误处理方式类(模块)3,此为订阅者
    /// </summary>
    public class Handle3
    {
        /// <summary>
        /// 出现错误时做出窗口抖动的处理
        /// </summary>
        public void ErrorHanding()
        {
            Console.WriteLine("出现错误!我抖!!!!!!!!!!!!!!!!!!!!!!!!");
        }
    }

专门进行错误处理的模块

/// <summary>
    /// 系统错误处理相关的类(模块),此为信息的发布者
    /// </summary>
    public class ErrorAbout
    {

        /// <summary>
        /// 错误处理的方法,主模块中通过调用此方法来触发一系列的错误处理
        /// </summary>
        public void ErrorHanding()
        {
            //实例化每一个订阅者,并调用其方法
            Handle1 handle1 = new Handle1();
            handle1.ErrorHanding();
            Handle2 handle2 = new Handle2();
            handle2.ErrorHanding();
            Handle3 handle3 = new Handle3();
            handle3.ErrorHanding();

        }
    }
主系统中:

class Program
    {
        static void Main(string[] args)
        {
            //假设在这个位置,系统出现了错误,需要进行错误处理
            Console.WriteLine("系统出现了严重错误,需要进行一些处理~~~");

            //实例化错误处理相关的类(发布者)
            ErrorAbout errorAbout = new ErrorAbout();
            //只要发布者的方法一执行,所有订阅者的方法也都会被执行
            errorAbout.ErrorHanding();


            Console.ReadKey();
        }
    }
运行结果如下:


这么做完全可以实现需要的功能

但是有何不妥呢?

在主模块中发现错误的时候new一个错误模块的实例,然后调用处理错误的方法
在错误模块中直接new各个子模块的实例,然后在处理错误的方法中依次执行
这样一来,错误模块和子模块之间就直接耦合在一起

这是面向过程的处理方式

在子模块方法发生改变的时候,或者错误模块需要添加新的处理错误的方法时
要对已经开发完毕的错误模块进行修改,违反了开放封闭原则
所以要对错误模块和子模块进行解耦(面向对象思想)


这时候就用到了观察者(Observer)模式,又称为发布-订阅模式等

实现的方法有两种

方法一:使用委托
方法二:使用接口
两种方法都实现了对错误模块和子模块的隔离
对两个模块的操作都是在主模块中完成的



Demo1:使用委托实现

具体错误处理方法的委托

/// <summary>
    /// 具体错误处理方法的委托
    /// </summary>
    public delegate void ErrorHandle();

/// <summary>
    /// 系统错误处理相关的类(模块),此为信息的发布者
    /// </summary>
    public class ErrorAbout
    {
        //定义一个 具体错误处理方法委托 的变量
        private ErrorHandle errorHandle;

        //向外界提供一个可以向内部委托变量添加的方法
        public void AddErrorHanding(ErrorHandle errorHandle)
        {
            //将传进来的方法加入委托变量中
            if (this.errorHandle == null)
            {
                this.errorHandle = new ErrorHandle(errorHandle);
            }
            else
            {
                this.errorHandle += new ErrorHandle(errorHandle);
            }
        }

        /// <summary>
        /// 错误处理的方法,主模块中通过调用此方法来触发一系列的错误处理
        /// </summary>
        public void ErrorHanding()
        {
            //调用委托,相当于调用了委托中的所有方法
            errorHandle();
        }
    }
在使用委托时要注意

不能直接让外界操作内部的委托

一定要封装一个方法提供外界以一个安全的方式来操作内部的委托(为什么说这是一个安全的方式呢?因为在这个方法里面只能给委托添加方法,不能进行其他的任何操作)

如果直接将委托变量暴露给外界

那么外界就可以调用委托变量的所有方法

有可能会造成将原本的方法删除或者覆盖等情况

(这就是为什么会有事件这个东西存在的原因)

这也是一种面向对象的思想


在主模块中

class Program
    {
        static void Main(string[] args)
        {
            //假设在这个位置,系统出现了错误,需要进行错误处理
            Console.WriteLine("系统出现了严重错误,需要进行一些处理~~~");

            //实例化错误处理相关的类(发布者)
            ErrorAbout errorAbout = new ErrorAbout();
            //向发布者添加订阅者
            Handle1 handle1 = new Handle1();
            errorAbout.AddErrorHanding(handle1.ErrorHanding);
            Handle2 handle2 = new Handle2();
            errorAbout.AddErrorHanding(handle1.ErrorHanding);
            Handle3 handle3 = new Handle3();
            errorAbout.AddErrorHanding(handle1.ErrorHanding);
            //只要发布者的方法一执行,所有订阅者的方法也都会被执行
            errorAbout.ErrorHanding();


            Console.ReadKey();
        }
    }
这样一来就实现了对错误模块和其他模块的解耦

任何错误具体的操作模块发生了变化

只要在其使用者--主模块中修改即可


Demo2:使用接口实现

首先需要提供一个统一的接口给具体的错误处理方式类(模块)

在发布者中可以通过这个接口调用实现了这个接口的所有订阅者


具体的错误处理方式类(模块)需要实现的接口

 /// <summary>
    /// 具体的错误处理方式类(模块)需要实现的接口,在发布者中通过此接口可以统一调用订阅者的方法
    /// </summary>
    public interface IHandle
    {
        void ErrorHanding();
    }


具体的错误处理方式类(模块)

 /// <summary>
    /// 具体的错误处理方式类(模块)1,此为订阅者
    /// </summary>
    public class Handle1:IHandle
    {
        /// <summary>
        /// 出现错误时做出发送邮件的处理
        /// </summary>
        public void ErrorHanding()
        {
            Console.WriteLine("出现错误!发送了一封邮件到管理员!");
        }
    }

/// <summary>
    /// 具体的错误处理方式类(模块)2,此为订阅者
    /// </summary>
    public class Handle2:IHandle
    {
        /// <summary>
        /// 出现错误时做出发出警报的处理
        /// </summary>
        public void ErrorHanding()
        {
            Console.WriteLine("出现错误!警报!!!!!!!!!!!!!!!!");
        }
    }

/// <summary>
        /// 出现错误时做出窗口抖动的处理
        /// </summary>
        public void ErrorHanding()
        {
            Console.WriteLine("出现错误!我抖!!!!!!!!!!!!!!!!!!!!!!!!");
        }


发布者

/// <summary>
    /// 系统错误处理相关的类(模块),此为信息的发布者
    /// </summary>
    public class ErrorAbout
    {
        /// <summary>
        /// 订阅者接口的集合
        /// </summary>
        private List<IHandle> handles = new List<IHandle>();

        /// <summary>
        /// 在主模块中可以通过此方法向 订阅者接口的集合 中添加新的订阅者(具体处理错误的方法)
        /// </summary>
        /// <param name="handle"></param>
        public void AddErrorHanding(IHandle handle)
        {
            handles.Add(handle);
        }

        /// <summary>
        /// 错误处理的方法,主模块中通过调用此方法来触发一系列的错误处理
        /// </summary>
        public void ErrorHanding()
        {
            //遍历订阅者接口的集合
            foreach (var handle in handles)
            {
                //执行集合中的每个错误处理的方法
                handle.ErrorHanding();
            }
        }
    }

主模块中

class Program
    {
        static void Main(string[] args)
        {
            //假设在这个位置,系统出现了错误,需要进行错误处理
            Console.WriteLine("系统出现了严重错误,需要进行一些处理~~~");

            //实例化错误处理相关的类(发布者)
            ErrorAbout errorAbout = new ErrorAbout();
            //向发布者添加订阅者
            errorAbout.AddErrorHanding(new Handle1());
            errorAbout.AddErrorHanding(new Handle2());
            errorAbout.AddErrorHanding(new Handle3());
            //只要发布者的方法一执行,所有订阅者的方法也都会被执行
            errorAbout.ErrorHanding();


            Console.ReadKey();
        }
    }


委托实现C#观察者模式简单例子下载:

点击打开链接

接口实现C#观察者模式简单例子下载:

点击打开链接






相关文章
|
1月前
|
设计模式 监控 Java
Kotlin - 改良设计模式 - 观察者模式
Kotlin - 改良设计模式 - 观察者模式
51 3
|
1月前
|
设计模式 监控 Java
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
|
2月前
|
设计模式 消息中间件 安全
C# 一分钟浅谈:观察者模式与订阅发布模式
【10月更文挑战第11天】本文介绍了观察者模式和订阅发布模式,这两种设计模式主要用于实现对象间的解耦。观察者模式通过事件和委托实现一个对象状态改变时通知多个依赖对象;订阅发布模式则通过事件聚合器实现发布者与订阅者之间的解耦。文章详细探讨了这两种模式的实现方式、常见问题及避免方法,帮助开发者在实际项目中更好地应用这些模式,提升代码的可维护性和扩展性。
78 1
|
2月前
|
设计模式 传感器
【设计模式】观察者模式(定义 | 特点 | Demo入门讲解)
【设计模式】观察者模式(定义 | 特点 | Demo入门讲解)
49 0
|
20天前
|
设计模式 消息中间件 搜索推荐
Java 设计模式——观察者模式:从优衣库不使用新疆棉事件看系统的动态响应
【11月更文挑战第17天】观察者模式是一种行为设计模式,定义了一对多的依赖关系,使多个观察者对象能直接监听并响应某一主题对象的状态变化。本文介绍了观察者模式的基本概念、商业系统中的应用实例,如优衣库事件中各相关方的动态响应,以及模式的优势和实际系统设计中的应用建议,包括事件驱动架构和消息队列的使用。
|
22天前
|
设计模式 监控 Java
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
36 1
|
1月前
|
设计模式 监控 Java
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
28 3
|
2月前
|
设计模式 监控 Java
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
36 9
|
2月前
|
设计模式 监控 Java
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
35 2
|
2月前
|
设计模式 监控 UED
设计模式之观察者模式
【10月更文挑战第12天】 观察者模式是一种行为型设计模式,定义了一对多的依赖关系,当一个对象状态改变时,所有依赖它的对象都会自动更新。主要由主题(被观察者)和观察者组成,实现对象间的松耦合,广泛应用于用户界面、事件驱动系统和数据监控等领域。
下一篇
DataWorks