帮你理清观察者模式和委托、事件的区别

本文介绍了C#中的委托、事件、Action和Func的概念,并通过实例展示了观察者模式的实现。观察者模式提供了一种解耦的编程思路,与委托不同,它不直接涉及数据结构。文中通过创建接口和对象实现了观察者模式,对比了使用观察者模式前后的代码组织方式,强调了其在代码维护和解耦合上的优势。此外,还提到了发布者订阅者模式作为更彻底的解耦方案。

观察者模式

观察者模式它其实是一种写代码的思路,首先本质上和委托的区别就是,一个是思路,一个是具体的数据结构,委托就是一个delegate,是可以直接在代码里声明的,但是观察者模式是通过一些数据结构按照特定的思路写出来,变成观察者模式。

那么到底什么是观察者模式呢?接下来就只能直接上代码了:

创建好接口,我们再来实现 ”被观察者“(Player)对象身上的逻辑:
接下来离观察者模式就还差最后一步了,在观察者的对象脚本上实现ITakeHitObserver接口,并通过AddObserver添加到被观察者的list中,这里我们假设有一个屏幕震动的脚本:
至此,一个简单的观察者模式就实现完了,当然,你还可以根据需求,在别的观察者上实现这个接口,比如受到攻击的时候,血条扣除相应的血量,这里就需要把接口方法加上一个参数传入扣除的血量,有兴趣的同学可以自己试试。
那么观察者模式对比普通的用代码实现有啥好处呢,我们来看看不用观察者模式的时候代码是怎么写的:
这样就会导致player里有一堆引用,并且很多逻辑调用的行数,这样后期维护起来就会变的非常困难,一旦哪个对象需要处理的方法要变,就得去改player的代码,但是用了观察者模式,只需要NotifyObservers()这个方法就可以调用到所有需要处理的地方,不是很爽吗?也实现了解耦。
可以发现整个观察者模式的实现,实际上和委托并没有任何关系,这下能分清观察者模式和委托的区别了吗?
其实还有一种完全解耦合的模式, 发布者订阅者模式 ,细心的同学可能发现了,观察者模式实现的时候,在观察者那边还是需要保留一份被观察者的引用,这样在复杂情况下的时候,就有可能会有多个不同被观察者的引用同时存在,当数量多的时候也会出现耦合的情况,那么这个时候发布者订阅者模式的完全解耦就派上用场了,这个模式就是基于委托的事件实现的,有兴趣的同学可以留言给我,如果有人想了解我就会再之后更新一篇发布者订阅者模式的介绍。
看完文章如果觉得对您有帮助的话,麻烦点一波关注哦!~ 有任何疑问和建议也欢迎在下方留言,大家一起探讨交流!谢谢大家!
<think>好的,用户想了解C#中的委托事件,包括它们的定义、区别应用场景。我需要先理清这两个概念的基础知识,然后比较它们的异同,再结合实际应用场景进行说明。 首先,委托(Delegate)在C#中是一种类型安全的函数指针,允许将方法作为参数传递。委托需要先定义签名,然后实例化并绑定具体方法。例如,定义一个无返回值无参数的委托,可以用public delegate void MyDelegate();,然后创建实例MyDelegate del = MethodName;。委托支持多播,也就是可以组合多个方法,按顺序执行。比如del += AnotherMethod;,这样调用del()时会依次执行MethodNameAnotherMethod。引用中提到的委托的应用场景包括回调机制多播能力,比如异步编程中的回调函数[^1][^4]。 接下来是事件(Event)。事件基于委托,提供了一种发布-订阅模型,用于在类内部声明,外部只能订阅或取消订阅。事件使用event关键字声明,如public event MyDelegate MyEvent;。事件的主要作用是封装委托,限制外部对委托的直接访问,只能通过+=-=来添加或移除处理程序。这样可以提高封装性安全性,比如避免外部直接触发事件或清空所有订阅者。引用中提到的事件应用场景包括工业控制跨线程的界面响应,比如在UI编程中,后台线程完成工作后通过事件通知主线程更新界面[^3][^4]。 区别方面,首先访问权限不同。委托的实例可以被外部直接调用,而事件只能在声明它的类内部触发。其次,事件提供了更好的封装,防止外部随意修改订阅列表,只能添加或移除处理程序。再者,事件更符合发布-订阅模式,适用于组件间的松耦合通信,而委托更多用于回调方法组合。例如,在WinForms中,按钮的Click事件允许外部订阅,但按钮类内部处理点击动作并触发事件,外部无法直接调用Click事件[^2]。 应用场景部分,委托常用于需要动态调用方法的情况,如LINQ中的Where方法接受委托参数来过滤元素。事件则用于对象状态变化时通知其他对象,如UI控件的事件处理、观察者模式实现等。引用中提到的工业控制跨线程界面响应是典型的事件应用场景,比如在工控系统中,传感器数据到达时触发事件,或者在多线程程序中,子线程完成任务后通过事件通知主线程更新UI,避免跨线程访问控件的问题[^1]。 需要注意用户可能混淆委托事件,尤其是在语法上的相似性。需要强调事件委托的封装,增强安全性封装性。同时,用户可能想知道如何选择使用委托还是事件,这时候应说明事件适合需要控制访问权限的场景,而委托适合需要灵活传递方法的情况。 最后,根据用户提供的引用,特别是引用[1][4],需要强调事件的多播特性应用场景,比如跨线程界面更新,这里可能涉及Invoke的使用,但事件本身并不处理线程问题,而是提供通知机制。同时,引用[3]提到的事件机制增强了解耦灵活性,这也是事件在大型应用中的优势所在。 总结回答结构:先分别讲解委托事件的定义及用法,再比较它们的区别,最后列举应用场景,并引用相关内容支持观点。</think>### C# 委托事件的定义、区别及应用场景 #### 一、**委托(Delegate)的定义及用法** 1. **定义** 委托是一种类型安全的函数指针,用于封装方法签名,允许将方法作为参数传递或存储。其核心作用是实现方法的动态调用多播能力。 语法示例: ```csharp public delegate void MyDelegate(string message); // 定义委托类型 MyDelegate del = ShowMessage; // 实例化委托并绑定方法 del("Hello"); // 调用委托 ``` 2. **关键特性** - **多播机制**:支持通过`+=``-=`绑定多个方法,调用时按顺序执行。 - **应用场景**:回调函数(如异步编程)、LINQ查询条件(如`Where`方法接受委托参数)[^4]。 --- #### 二、**事件(Event)的定义及用法** 1. **定义** 事件委托的封装,基于发布-订阅模型,用于在对象状态变化时通知其他对象。事件只能在声明它的类内部触发,外部只能订阅或取消订阅。 语法示例: ```csharp public delegate void EventHandler(object sender, EventArgs e); // 标准事件委托定义 public event EventHandler Clicked; // 声明事件 private void OnClicked() { Clicked?.Invoke(this, EventArgs.Empty); // 触发事件(仅限类内部) } ``` 2. **关键特性** - **访问控制**:外部代码只能通过`+=`订阅或`-=`取消事件处理程序,无法直接调用或清空事件。 - **线程安全**:常用于跨线程更新UI(如WinForms中通过`Invoke`触发事件)[^1]。 --- #### 三、**委托事件区别** | **特性** | **委托** | **事件** | |------------------|-----------------------------|-----------------------------| | 访问权限 | 外部可直接调用或修改 | 只能在声明类内部触发 | | 封装性 | 低(暴露委托实例) | 高(隐藏委托实例) | | 多播支持 | 支持 | 支持(更常用) | | 典型应用 | 回调、方法组合 | UI交互、观察者模式 | --- #### 四、**应用场景** 1. **委托的典型场景** - **动态方法调用**:例如LINQ的`Where`方法接受委托参数。 - **异步编程**:如`BeginInvoke`结合回调委托处理异步结果[^4]。 2. **事件的典型场景** - **UI交互**:按钮点击、文本框输入等控件事件。 - **跨线程通信**:后台线程完成任务后通过事件通知主线程更新界面。 - **工业控制**:传感器数据到达时触发事件通知处理逻辑。 --- #### 五、**代码示例** ```csharp // 委托定义与使用 public delegate void LogHandler(string message); public class Logger { public LogHandler LogEvent; // 委托变量 public void Log(string message) => LogEvent?.Invoke(message); } // 事件定义与使用 public class Button { public event EventHandler Clicked; // 事件声明 public void Click() => Clicked?.Invoke(this, EventArgs.Empty); } // 订阅事件 Button btn = new Button(); btn.Clicked += (sender, e) => Console.WriteLine("Button clicked!"); ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值