.NET 设计模式—观察者模式(Observer Pattern)
简介
在.NET中,观察者模式是一种设计模式,它允许对象之间进行一对多的依赖关系。当一个对象的状态发生变化时,所有依赖于它的对象都会收到通知并自动更新。这种模式在事件驱动的设计中非常常见。
在.NET中实现观察者模式,通常涉及到定义一个抽象的观察者接口和一个可被观察的对象。这个可被观察的对象维护一个观察者的列表,并在状态改变时通知所有观察者。
角色
- 抽象主题角色(Subject):抽象主题把所有观察者对象的引用保存在一个列表中,并提供增加和删除观察者对象的操作,抽象主题角色又叫做抽象被观察者角色,一般由抽象类或接口实现。
- 抽象观察者角色(Observer):为所有具体观察者定义一个接口,在得到主题通知时更新自己,一般由抽象类或接口实现。
- 具体主题角色(ConcreteSubject):实现抽象主题接口,具体主题角色又叫做具体被观察者角色。
- 具体观察者角色(ConcreteObserver):实现抽象观察者角色所要求的接口,以便使自身状态与主题的状态相协调。
优点
- 观察者模式实现了表示层和数据逻辑层的分离,并定义了稳定的更新消息传递机制,并抽象了更新接口,使得可以有各种各样不同的表示层,即观察者。
- 观察者模式在被观察者和观察者之间建立了一个抽象的耦合,被观察者并不知道任何一个具体的观察者,只是保存着抽象观察者的列表,每个具体观察者都符合一个抽象观察者的接口。
- 观察者模式支持广播通信。被观察者会向所有的注册过的观察者发出通知。
缺点
- 如果一个被观察者有很多直接和间接的观察者时,将所有的观察者都通知到会花费很多时间。
- 虽然观察者模式可以随时使观察者知道所观察的对象发送了变化,但是观察者模式没有相应的机制使观察者知道所观察的对象是怎样发生变化的。
- 如果在被观察者之间有循环依赖的话,被观察者会触发它们之间进行循环调用,导致系统崩溃,在使用观察者模式应特别注意这点。
应用场景
- 当需要将一个对象的状态变化通知给其他多个对象时,可以使用观察者模式;
- 当一个对象的改变需要同时改变其他对象的状态或者操作时,可以使用观察者模式;
- 当一个抽象模型有两个方面,其中一个方面依赖于另一个方面时,可以使用观察者模式。例如,模型和视图之间的关系,模型驱动视图的更新,而视图反过来也要反映到模型中;
- 当一个对象必须通知其他对象,但是你不知道这些对象是谁时,可以使用观察者模式。例如,你不知道哪些用户订阅了你的微信公众号,但你需要在每次发布新文章时通知所有订阅用户;
- 当一个对象需要有别的对象来协助完成某项工作,并且不希望知道具体协助它的对象时,可以使用观察者模式。例如,一个员工完成某项任务需要得到经理的批准,但他并不知道具体是哪个经理会批准。
实现
- 定义观察者接口
public interface IObserver
{void Update(string message); // 或者根据具体需求定义其他方法
}
- 定义可观察的对象,它包含一个观察者列表,并提供注册和通知观察者的方法
using System.Collections.Generic;public class Observable
{private List<IObserver> observers = new List<IObserver>();private string state;// 注册观察者public void RegisterObserver(IObserver observer){observers.Add(observer);}// 移除观察者(可选)public void RemoveObserver(IObserver observer){observers.Remove(observer);}// 通知所有观察者(状态改变时调用)protected void NotifyObservers(string message){foreach (var observer in observers){observer.Update(message);}}// 改变状态并通知观察者(这里假设状态是一个字符串)public void ChangeState(string newState){state = newState;NotifyObservers("State changed to: " + state); // 通知所有观察者状态已改变及新状态信息}
}
- 实现具体的观察者类,它实现观察者接口并定义如何响应通知
public class ConcreteObserver : IObserver
{public void Update(string message){// 在这里处理接收到的通知,比如更新UI、记录日志等操作。Console.WriteLine("Observer received: " + message); // 仅作为示例,实际实现根据需求来定。}
}
- 上层应用调用
class Program
{static void Main(string[] args){// 创建可观察对象和观察者实例。Observable observable = new Observable();ConcreteObserver observer = new ConcreteObserver(); // 可以创建多个观察者实例。observable.RegisterObserver(observer); // 注册观察者到可观察对象。// ... 在程序的其他部分,当需要通知观察者时调用可观察对象的ChangeState方法 observable.ChangeState("New state information");。这样就会触发通知所有注册的观察者。}
}
相关文章:
.NET 设计模式—观察者模式(Observer Pattern)
简介 在.NET中,观察者模式是一种设计模式,它允许对象之间进行一对多的依赖关系。当一个对象的状态发生变化时,所有依赖于它的对象都会收到通知并自动更新。这种模式在事件驱动的设计中非常常见。 在.NET中实现观察者模式,通常涉…...
EasyUI Jquery 学习笔记 ——DataGrid(数据网格)与 Tree(树)详细版
1. DataGrid(数据网格)与 Tree(树) 1.1 Datagrid 数据网格 扩展自 $.fn.panel.defaults。通过 $.fn.datagrid.defaults 重写默认的 defaults。 数据网格(datagrid)以表格格式显示数据,并为选择、排序、分组和编辑数据提供了丰富的支持。数据网格(datagrid)的设计目…...
JAVA发票验真接口、票据ocr、数电票在线查验真伪
发票验真接口,,实时联网核验发票真伪,查验一致返回全票面信息,支持查验增值税发票管理系统开具的发票,支持批量核验发票,翔云发票查验送发票识别,助您摆脱手动输入繁琐,提升工作效率。 发票查验接口适用于银行、金融、代理记账等发票管理数量…...
el-date-picker调用回车事件
elementui的el-date-picker想要调用回车事件: <el-date-pickerv-model"state.date"type"date"value-format"YYYY-MM-DD HH:mm:ss"placeholder"选择日期"clearablekeydown.enter"handleDown"></el-date-…...
js学习总结
这里写目录标题 前情提要JavaScript书写位置1. 内部javaScript (不常用)2. 外部javaScript (常用)3.内联javaScript (常用) js中的输入和输出输出语法1. document.write()2. alert()3. console.log() 输入语法prompt() 前情提要 1. 在javaScript中的 分号 是可以省略的JavaScr…...
MES实施优势有哪些?MES制造执行系统的主要内容
各个行业之间也开始进入到了激烈的竞争当中,很多企业为了能够有效提升企业竞争力,都会通过提升自身实力的方式来提升竞争力。一些制造业也会在经营过程当中使用到MES系统,那么,mes系统的优势有哪些呢? 1、优化企业现场…...
ChatGPT 和 Elasticsearch:使用 Elastic 数据创建自定义 GPT
作者:Sandra Gonzales ChatGPT Plus 订阅者现在有机会创建他们自己的定制版 ChatGPT,称为 GPT,这替代了之前博客文章中讨论的插件。基于本系列的第一部分的基础 —— 我们深入探讨了在 Elastic Cloud 中设置 Elasticsearch 数据和创建向量嵌…...
废品回收 小程序+APP
用户实名认证、回收员实名认证、后台审核、会员管理、回收员管理、订单管理、提现管理、地图、档案管理。 支持,安卓APP、苹果APP、小程序 流程: 一、用户端下单,地图选择上门位置、填写具体位置、废品名称、预估重量、选择是企业废旧、家…...
下载好了annaconda,但是在创建一个新的Conda虚拟环境报错
文章目录 问题描述:解决方案1.生成一个配置文件 问题总结 问题描述: ProxyError(MaxRetryError(“HTTPSConnectionPool(host‘repo.anaconda.com’, port443): Max retries exceeded with url: /pkgs/pro/win-64/repodata.json.bz2 (Caused by ProxyErr…...
如何安装MacOS的虚拟机?mac安装虚拟机的步骤 虚拟机安装MacOS VMware Fusion和Parallels Desktop19
要在Mac上运行MacOS的虚拟机,常用的方法是使用虚拟化软件如VMware Fusion或Parallels Desktop。 以下是安装MacOS的虚拟机的主要步骤: 1. 检查系统要求:确定您的Mac硬件和操作系统满足安装要求。您需要一台具备足够性能的Mac,并…...
Flutter 中 AutomaticKeepAliveClientMixin 的介绍及使用
在 Flutter 中,当你在一个页面中滑动列表或者进行其他一些操作时,如果你返回到该页面,可能会发现之前的状态已经丢失了。这在某些情况下可能是不可取的,特别是当你想要保留之前的状态,而不是每次都重新加载页面时。 为…...
注意力机制篇 | YOLOv8改进之清华开源ACmix:自注意力和CNN的融合 | 性能速度全面提升
前言:Hello大家好,我是小哥谈。混合模型ACmix将自注意力机制和卷积神经网络进行整合,使其同时具有自注意力机制和卷积神经网络的优点。这是清华大学、华为和北京人工智能研究院共同发布在2022年CVPR中的论文。ACmix结合了自注意力机制和卷积神经网络的优势,以提高模型的性能…...
Go语言支持重载吗?如何实现重写?
Go语言不支持传统意义上的函数和方法重载。在Go语言中,函数名或方法名不能相同但参数列表不同,因为这会导致编译错误。 然而,可以通过方法重写(override)来实现类似的功能。方法重写是指在子类中定义一个与父类同名的…...
Spring中基于事件监听驱动 和 线程池的异步任务
文章目录 事件监听驱动 与 异步事件源ApplicationContextAware接口 发布事件事件实体监听事件实现异步注入綫程池 事件驱动机制,与MQ消息队列比较 事件监听驱动 与 异步 事件监听驱动优点:解耦,将 事件和业务进行解耦,通过Asyc注解…...
C++ 优先级队列用法详解与模拟实现
文章目录 C 优先级队列用法与模拟实现介绍用法头文件1.创建优先级队列priority_queue 2. 插入元素push 3. 删除元素pop 访问顶部元素top 检查优先级队列的大小size 检查优先级队列是否为空empty 模拟实现 C 优先级队列用法与模拟实现 介绍 优先级队列(Priority Qu…...
Linux进阶之旅:深入探索Linux的高级功能
文章目录 Linux进阶之旅:深入探索Linux的高级功能1. Shell脚本编程2. 进程管理3. 网络管理4. 文本处理5. 系统监控6. 总结 Linux进阶之旅:深入探索Linux的高级功能 在上一篇博客中,我们对Linux操作系统进行了入门级的介绍,包括Linux的特点、发行版、安装方法以及基本使用。接下…...
【Java】内存可见性问题是什么?
文章目录 内存模型内存可见性解决方案volatile 内存模型 什么是JAVA 内存模型? Java Memory Model (JAVA 内存模型)是描述线程之间如何通过内存(memory)来进行交互。 具体说来, JVM中存在一个主存区(Main Memory或Java Heap Mem…...
Guava里一些比较常用的工具
随着java版本的更新提供了越来越多的语法和工具来简化日常开发,但是我们一般用的比较早的版本所以体验不到。这时就用到了guava这个包。guava提供了很多方便的工具方法,solar框架就依赖了guava的16.0.1版本,这里稍微介绍下。 一、集合工具类…...
在windows系统中【.gz.tar】和【.whl】文件分别应该怎么下载到conda的某个虚拟环境中
在 Windows 系统中,你可以按照以下步骤将 .gz.tar 和 .whl 文件下载到 Conda 的某个虚拟环境中: 激活虚拟环境:打开 Anaconda Prompt 或者命令行窗口,使用以下命令激活你想要安装文件的虚拟环境: conda activate <虚…...
Rust - 数据类型
Rust 是静态编译语言,在编译时必须知道所有变量的类型。 基于使用的值,编译器通常能推断出它的具体类型,但如果可能的类型比较多,例如把String转换为整数的parse方法,就必须添加类型的标注,否则编译会报错…...
OpenLayers 可视化之热力图
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 热力图(Heatmap)又叫热点图,是一种通过特殊高亮显示事物密度分布、变化趋势的数据可视化技术。采用颜色的深浅来显示…...
Java 语言特性(面试系列1)
一、面向对象编程 1. 封装(Encapsulation) 定义:将数据(属性)和操作数据的方法绑定在一起,通过访问控制符(private、protected、public)隐藏内部实现细节。示例: public …...
Linux相关概念和易错知识点(42)(TCP的连接管理、可靠性、面临复杂网络的处理)
目录 1.TCP的连接管理机制(1)三次握手①握手过程②对握手过程的理解 (2)四次挥手(3)握手和挥手的触发(4)状态切换①挥手过程中状态的切换②握手过程中状态的切换 2.TCP的可靠性&…...
新能源汽车智慧充电桩管理方案:新能源充电桩散热问题及消防安全监管方案
随着新能源汽车的快速普及,充电桩作为核心配套设施,其安全性与可靠性备受关注。然而,在高温、高负荷运行环境下,充电桩的散热问题与消防安全隐患日益凸显,成为制约行业发展的关键瓶颈。 如何通过智慧化管理手段优化散…...
python执行测试用例,allure报乱码且未成功生成报告
allure执行测试用例时显示乱码:‘allure’ �����ڲ����ⲿ���Ҳ���ǿ�&am…...
使用 SymPy 进行向量和矩阵的高级操作
在科学计算和工程领域,向量和矩阵操作是解决问题的核心技能之一。Python 的 SymPy 库提供了强大的符号计算功能,能够高效地处理向量和矩阵的各种操作。本文将深入探讨如何使用 SymPy 进行向量和矩阵的创建、合并以及维度拓展等操作,并通过具体…...
iOS性能调优实战:借助克魔(KeyMob)与常用工具深度洞察App瓶颈
在日常iOS开发过程中,性能问题往往是最令人头疼的一类Bug。尤其是在App上线前的压测阶段或是处理用户反馈的高发期,开发者往往需要面对卡顿、崩溃、能耗异常、日志混乱等一系列问题。这些问题表面上看似偶发,但背后往往隐藏着系统资源调度不当…...
Scrapy-Redis分布式爬虫架构的可扩展性与容错性增强:基于微服务与容器化的解决方案
在大数据时代,海量数据的采集与处理成为企业和研究机构获取信息的关键环节。Scrapy-Redis作为一种经典的分布式爬虫架构,在处理大规模数据抓取任务时展现出强大的能力。然而,随着业务规模的不断扩大和数据抓取需求的日益复杂,传统…...
Django RBAC项目后端实战 - 03 DRF权限控制实现
项目背景 在上一篇文章中,我们完成了JWT认证系统的集成。本篇文章将实现基于Redis的RBAC权限控制系统,为系统提供细粒度的权限控制。 开发目标 实现基于Redis的权限缓存机制开发DRF权限控制类实现权限管理API配置权限白名单 前置配置 在开始开发权限…...
41道Django高频题整理(附答案背诵版)
解释一下 Django 和 Tornado 的关系? Django和Tornado都是Python的web框架,但它们的设计哲学和应用场景有所不同。 Django是一个高级的Python Web框架,鼓励快速开发和干净、实用的设计。它遵循MVC设计,并强调代码复用。Django有…...
