设计模式:观察者模式(C#、JAVA、JavaScript、C++、Python、Go、PHP)
简介:
观察者模式,它是一种行为型设计模式,它允许一个对象自动通知其依赖者(观察者)状态的变化。当被观察者的状态发生改变时,它会通知所有的观察者对象,使他们能够及时做出响应。在观察者模式中,被观察者和观察者对象之间不需要知道对方的具体实现,只需要知道对方的接口,从而避免了紧耦合的关系。
在观察者模式中,有以下几个核心组成部分:
1、被观察者(Subject):它是一个抽象类或接口,维护一个观察者对象的列表,并定义了注册和删除观察者对象的方法。当被观察者的状态发生变化时,它负责通知所有已注册的观察者对象。
2、具体被观察者(ConcreteSubject):它是被观察者的具体实现,它维护一个状态,并定义了存储状态的方法。当它的状态发生变化时,它会通知所有已注册的观察者对象。
3、观察者(Observer):它是一个抽象类或接口,定义了更新方法以响应被观察者的状态变化。
4、具体观察者(ConcreteObserver):它是观察者的具体实现,实现了更新方法以响应被观察者的状态变化,并执行一些具体的业务逻辑处理。
在观察者模式中,被观察者和观察者之间形成了一种“一对多”的关系,当被观察者的状态发生变化时,所有注册的观察者都会得到通知并做出相应的响应。这种设计模式使得观察者与被观察者之间的耦合度降低,符合开闭原则,可以动态地增加或者删除观察者对象。然而,也需要注意避免出现循环依赖的问题,并确保在适当的时候移除观察者对象,避免内存泄漏的问题。
观察者模式的使用场景:
1、关联行为场景:观察者模式适用于建立一套触发机制的场景,例如用户关注某个商品的价格,当商品降价时进行通知,这样用户和商品产生了关联,触发机制就是商品降价。
2、事件处理系统:观察者模式可以用于实现事件处理系统,例如在购物网站中,多个用户关注某商品后,当商品降价时,就会自动通知关注该商品的用户。
总的来说,观察者模式适用于需要实现一对多的依赖关系,并且需要在对象状态改变时自动通知所有依赖者的场景。
观察者模式的创建步骤:
1、创建被观察者(Watched)类,该类通常包含一个观察者列表,以及一个用于添加、删除和通知观察者的方法。
2、创建观察者(Watcher)类,该类通常包含一个更新方法,用于在被观察者状态发生改变时更新自身状态。
3、在被观察者类中添加注册和注销观察者的方法,以便于添加和删除观察者对象。
4、在被观察者类中实现通知观察者的方法,以便于在状态发生改变时通知所有观察者对象。
5、创建具体被观察者(ConcreteWatched)类,该类继承自被观察者类,并实现具体的业务逻辑。
6、创建具体观察者(ConcreteWatcher)类,该类继承自观察者类,并实现具体的业务逻辑。
7、将具体被观察者和具体观察者对象进行组合,以便于在被观察者状态发生改变时通知所有观察者对象。
以上是观察者模式的基本创建步骤,需要注意的是,在实际应用中可能需要根据具体情况进行调整和优化。
观察者模式的优点,主要包括:
1、实现表示层和数据逻辑层的分离,并定义了稳定的消息更新传递机制,抽象了更新接口,使得可以有各种各样不同的表示层充当具体观察者角色。
2、在观察目标和观察者之间建立一个抽象的耦合,观察目标只需要维持一个抽象观察者的集合,无须了解其具体观察者。由于观察目标和观察者没有紧密地耦合在一起,因此它们可以属于不同的抽象化层次。
3、支持广播通信,观察目标会向所有已注册的观察者对象发送通知,简化了一对多系统设计的难度。
4、符合“开闭原则”的要求,增加新的具体观察者无须修改原有系统代码,在具体观察者与观察目标之间不存在关联关系的情况下,增加新的观察目标也很方便。
观察者模式的缺点,主要包括:
1、如果一个观察目标对象有很多直接和间接观察者,将所有的观察者都通知到会花费很多时间。
2、如果在观察者和观察目标之间存在循环依赖,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。
3、观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。
因此,在使用观察者模式时需要注意以上问题,避免出现不必要的缺陷。
示例:
一、C#观察者模式
以下是一个示例,展示了如何在C#中实现观察者模式:
//首先,定义一个被观察者接口:
public interface ISubject
{ void Register(IObserver observer); void Remove(IObserver observer); void Notify();
}
//然后,定义一个具体被观察者类:
public class ConcreteSubject : ISubject
{ private List<IObserver> observers; private string state; public ConcreteSubject() { observers = new List<IObserver>(); } public void Register(IObserver observer) { observers.Add(observer); } public void Remove(IObserver observer) { observers.Remove(observer); } public void Notify() { foreach (var observer in observers) { observer.Update(state); } } public void SetState(string state) { this.state = state; Notify(); }
}
//接下来,定义一个观察者接口:
public interface IObserver
{ void Update(string state);
}
//最后,定义一个具体观察者类:
public class ConcreteObserver : IObserver
{ private string name; public ConcreteObserver(string name) { this.name = name; } public void Update(string state) { Console.WriteLine("{0} received update and the new state is {1}", name, state); }
}
//接下来,可以创建一个具体的被观察者和多个具体观察者,并实现它们之间的交互:
public static void Main(string[] args){ISubject subject = new ConcreteSubject(); IObserver observer1 = new ConcreteObserver("Observer 1");IObserver observer2 = new ConcreteObserver("Observer 2"); IObserver observer3 = new ConcreteObserver("Observer 3"); subject.Register(observer1); subject.Register(observer2); subject.Register(observer3); subject.SetState("New State");
}
在这个示例中,我们创建了一个被观察者对象subject和一个观察者对象observer1、observer2和observer3。我们将这些观察者对象注册到被观察者对象subject中,然后调用subject的SetState方法来改变其状态。当状态发生变化时,所有注册的观察者都会自动收到通知并执行Update方法。
在这个例子中,我们只是简单地打印出每个观察者的名称和新的状态。你可以根据自己的需求扩展这个示例。
二、java观察者模式
观察者模式通常通过以下方式实现:
public interface Subject { void register(Observer observer); void remove(Observer observer); void notifyObservers(String message);
}
public class ConcreteSubject implements Subject { private List<Observer> observers; private String message; public ConcreteSubject() { observers = new ArrayList<>(); } @Override public void register(Observer observer) { observers.add(observer); } @Override public void remove(Observer observer) { observers.remove(observer); } @Override public void notifyObservers(String message) { for (Observer observer : observers) { observer.update(message); } } public void setMessage(String message) { this.message = message; notifyObservers(message); }
} public interface Observer { void update(String message);
}
class ConcreteObserver implements Observer { private String name; public ConcreteObserver(String name) { this.name = name; } @Override public void update(String message) { System.out.println(name + " received update with message: " + message); }
}
public class Main { public static void main(String[] args) { Subject subject = new ConcreteSubject(); Observer observer1 = new ConcreteObserver("Observer 1"); Observer observer2 = new ConcreteObserver("Observer 2"); Observer observer3 = new ConcreteObserver("Observer 3"); subject.register(observer1); subject.register(observer2); subject.register(observer3); subject.setMessage("Hello World!"); }
}
三、javascript观察者模式
在JavaScript中实现观察者模式,通常需要定义一个被观察者(Subject)和一个或多个观察者(Observer)。被观察者维护一个观察者列表,并在状态发生变化时遍历这个列表并调用每个观察者的更新方法。
下面是一个简单的JavaScript观察者模式的代码示例:
class Subject { constructor() { this.observers = []; } subscribe(observer) { this.observers.push(observer); } unsubscribe(observer) { this.observers = this.observers.filter(obs => obs !== observer); } notify(message) { this.observers.forEach(observer => observer.update(message)); }
} class Observer { constructor(name) { this.name = name; } update(message) { console.log(`${this.name} received update with message: ${message}`); }
} // 使用示例
const subject = new Subject();
const observer1 = new Observer("Observer 1");
const observer2 = new Observer("Observer 2");
const observer3 = new Observer("Observer 3");
subject.subscribe(observer1);
subject.subscribe(observer2);
subject.subscribe(observer3);
subject.notify("Hello World!");
四、C++观察者模式
以下是在C++中实现观察者模式:
//定义一个观察者接口
class Observer {
public: virtual void update(Subject* subject) = 0;
};
//定义一个被观察者接口
class Subject {
public: virtual void registerObserver(Observer* observer) = 0; virtual void removeObserver(Observer* observer) = 0; virtual void notifyObservers() = 0;
};
//创建一个具体被观察者类
class ConcreteSubject : public Subject {
private: std::vector<Observer*> observers; public: void registerObserver(Observer* observer) override { observers.push_back(observer); } void removeObserver(Observer* observer) override { for (auto it = observers.begin(); it != observers.end(); ++it) { if (*it == observer) { observers.erase(it); break; } } } void notifyObservers() override { for (auto observer : observers) { observer->update(this); } }
};
//创建一个具体观察者类
class ConcreteObserver : public Observer {
private: std::string name; public: ConcreteObserver(std::string name) : name(name) {} void update(Subject* subject) override { std::cout << name << " received update." << std::endl; }
};
//使用示例:
int main() { ConcreteSubject subject; ConcreteObserver observer1("Observer 1"); ConcreteObserver observer2("Observer 2"); ConcreteObserver observer3("Observer 3"); subject.registerObserver(&observer1); subject.registerObserver(&observer2); subject.registerObserver(&observer3); subject.notifyObservers(); // 输出:Observer 1 received update. Observer 2 received update. Observer 3 received update. subject.removeObserver(&observer2); // 删除一个观察者 subject.notifyObservers(); // 输出:Observer 1 received update. Observer 3 received update. return 0;
}
五、python观察者模式
在Python中实现观察者模式,通常需要定义一个被观察者类和一个或多个观察者类。被观察者类维护一个观察者列表,并在状态发生变化时遍历这个列表并调用每个观察者的更新方法。
以下是在python中实现观察者模式:
class Subject: def __init__(self): self._observers = [] def attach(self, observer): self._observers.append(observer) def detach(self, observer): self._observers.remove(observer) def notify(self, value=None): for observer in self._observers: observer.update(value) class Observer: def update(self, value): pass class ConcreteObserver(Observer): def update(self, value): print(f"Observer received update with value: {value}") # 使用示例
subject = Subject()
observer1 = ConcreteObserver()
observer2 = ConcreteObserver()
observer3 = ConcreteObserver()
subject.attach(observer1)
subject.attach(observer2)
subject.attach(observer3)
subject.notify(100) # 输出:Observer received update with value: 100 Observer received update with value: 100 Observer received update with value: 100
subject.detach(observer2) # 删除一个观察者
subject.notify(200) # 输出:Observer received update with value: 200 Observer received update with value: 200
六、go观察者模式
以下是一个示例,展示了如何在go中实现观察者模式:
type Subject struct { observers []Observer
} func (s *Subject) Attach(observer Observer) { s.observers = append(s.observers, observer)
} func (s *Subject) Notify() { for _, observer := range s.observers { observer.Update() }
} typeObserver interface { Update()
} typeConcreteObserver struct { name string
} func (o *ConcreteObserver) Update() { fmt.Printf("Observer %s received update.\n", o.name)
}
在这个示例中,我们定义了一个被观察者结构体Subject,它维护一个观察者列表observers。我们定义了一个Attach方法用于将一个观察者添加到观察者列表中,以及一个Notify方法用于遍历观察者列表并调用每个观察者的Update方法。我们定义了一个观察者接口Observer,它包含一个Update方法。最后,我们创建了一个具体观察者结构体ConcreteObserver,它实现了Observer接口的Update方法。在主函数中,我们创建了一个被观察者对象subject和一个具体观察者对象observer,并将它们分别添加到被观察者和观察者列表中。然后我们调用被观察者的Notify方法来通知所有注册的观察者状态变化。
七、PHP观察者模式
以下是一个示例,展示了如何在PHP中实现观察者模式:
//定义一个主题接口(Subject):
interface Subject { public function attach(Observer $observer); public function detach(Observer $observer); public function notify(Observer $observer);
}
//定义一个具体主题类(ConcreteSubject):
class ConcreteSubject implements Subject { private $observers = []; private $state; public function attach(Observer $observer) { $this->observers[] = $observer; } public function detach(Observer $observer) { $index = array_search($observer, $this->observers); if ($index !== false) { unset($this->observers[$index]); } } public function notify(Observer $observer) { foreach ($this->observers as $observer) { $observer->update($this->state); } } public function setState($state) { $this->state = $state; $this->notify($this->observers); }
}
//定义一个观察者接口(Observer):
interface Observer { public function update($state);
}
//定义一个具体观察者类(ConcreteObserver):
class ConcreteObserver implements Observer { private $name; public function __construct($name) { $this->name = $name; } public function update($state) { echo "Observer {$this->name} received update with state: {$state}\n"; }
}// 创建具体观察者对象
$observer1 = new ConcreteObserver("Observer 1");
$observer2 = new ConcreteObserver("Observer 2");
$observer3 = new ConcreteObserver("Observer 3"); // 创建具体主题对象并附加观察者对象
$subject = new ConcreteSubject();
$subject->attach($observer1);
$subject->attach($observer2);
$subject->attach($observer3); // 设置主题状态并通知观察者对象更新状态信息
$subject->setState("new state");
《完结》
相关文章:

设计模式:观察者模式(C#、JAVA、JavaScript、C++、Python、Go、PHP)
简介: 观察者模式,它是一种行为型设计模式,它允许一个对象自动通知其依赖者(观察者)状态的变化。当被观察者的状态发生改变时,它会通知所有的观察者对象,使他们能够及时做出响应。在观察者模式…...
kotling构造函数
Kotlin-继承与构造函数 - 简书 (jianshu.com) Kotlin语言中的继承与构造函数(详解)_kotlin 继承 构造函数_young螺母的博客-CSDN博客...

SpringMVC - 详解RESTful
文章目录 1. 简介2. RESTful的实现3.HiddenHttpMethodFilter4. RESTful案例1、准备工作2、功能清单3、具体功能:访问首页a>配置view-controllerb>创建页面 4、具体功能:查询所有员工数据a>控制器方法b>创建employee_list.html 5、具体功能&a…...

html表格标签
<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Title</title> </head> <body><!--表格table 行 tr 列 td --> <table border"1px"><tr> <!--colsp…...

Node.JS---npm相关
文章目录 前言一、package.json配置项version:1.0.0devDependenciesdependenciespeerDependenciesoptionalDependencies 二、npm命令1、npm config listxmzs使用2、npm installpackage-lock.json作用 3、npm run4、 查看全局安装的可执行文件 npm生命周期npxnpx简介…...

Flutter的Don‘t use ‘BuildContext‘s across async gaps警告解决方法
文章目录 问题有问题的源码 问题原因问题分析Context的含义BuildContext的作用特殊情况 解决方法 问题 Flutter开发中遇到Don’t use BuildContext’s across async gaps警告 有问题的源码 if (await databaseHelper.isDataExist(task.title)) {showDialog(context: context,…...

Nginx 实战教程
本篇博客我会演示日常的工作中,我们是怎么利用nginx部署项目的。我们以部署一套前后分离的项目为本次讲述的内容 一、搭建后端项目 创建一个最简单的springboot项目: 只需要依赖一个web模块即可: 提供一个api接口,可以获取服务端…...
Web自动化——python
文章目录 1.八大元素定位2.元素基本操作3.浏览器常用操作4.获取元素信息的常用方法5.鼠标和键盘相关操作6.元素等待1.隐式等待2.显示等待 7.下拉选择框8.弹出框9.滚动条操作10.frame表单的切换11.多窗口切换12.窗口截图、验证码处理 1.八大元素定位 元素属性定位:id…...
华为OD 整数最小和(100分)【java】A卷+B卷
华为OD统一考试A卷+B卷 新题库说明 你收到的链接上面会标注A卷还是B卷。目前大部分收到的都是B卷。 B卷对应20022部分考题以及新出的题目,A卷对应的是新出的题目。 我将持续更新最新题目 获取更多免费题目可前往夸克网盘下载,请点击以下链接进入: 我用夸克网盘分享了「华为O…...
正则表达式:文本处理中的瑞士军刀
正则表达式是用于提取字符串规律的规则,通过特定语法表达,以匹配符合该规律的字符串。它具有通用性,不仅适用于Python,也可用于其他编程语言。 下面我用Python的re模块来进行实战演示:(记得import re&…...

WebSocket 入门案例
目录 WebSocket入门案例WebSocket-server新增项目:添加依赖:yml:启动类: frontend-server前端项目:添加依赖:添加yml:启动类:前端引入JS:前端页面:后端代码:测试: WebSocket 入门案…...
华为OD 最大社交距离(100分)【java】A卷+B卷
华为OD统一考试A卷+B卷 新题库说明 你收到的链接上面会标注A卷还是B卷。目前大部分收到的都是B卷。 B卷对应20022部分考题以及新出的题目,A卷对应的是新出的题目。 我将持续更新最新题目 获取更多免费题目可前往夸克网盘下载,请点击以下链接进入: 我用夸克网盘分享了「华为O…...
Nginx缓存
Nginx缓存 一般情况下系统用到的缓存有三种 服务端缓存:缓存存在后端服务器,如redis 代理缓存:缓存存储在代理服务器或中间件,内容从后端服务器获取,保存在本地 客户端缓存:缓存在浏览器 [ ] 什么时候会出现…...

Pyecharts绘图教程(2)—— 绘制多种折线图(Line)参数说明+代码实战
文章目录 🎯 1 简介🎯 2 图表配置项2.1 导入模块2.2 数据配置项2.3 全局配置项 🎯 3 代码实战3.1 基础折线3.2 平滑曲线(is_smooth)3.3 阶梯折线(is_step)3.4 空值过渡(is_connect_n…...

oracle实现搜索不区分大小写
<if test"code ! null and code ! ">and upper(code) like upper(%${code}%) </if>关键字upper...

C++中->与.的区别
在类中 在 C 中,-> 和 . 都可以用于访问类的成员变量和成员函数。但它们在使用上有一些区别: 1. 对于指针类型的对象,必须使用 -> 来访问其成员;而对于非指针类型的对象,则需要使用 . 。 2. -> 运算符在实…...

大语言模型(LLM)综述(二):开发大语言模型的公开可用资源
A Survey of Large Language Models 前言3. RESOURCES OF LLMS3.1 公开可用的模型CheckPoints或 API3.2 常用语料库3.3 库资源 前言 随着人工智能和机器学习领域的迅速发展,语言模型已经从简单的词袋模型(Bag-of-Words)和N-gram模型演变为更…...

【vSphere 8 自签名证书】企业 CA 签名证书替换 vSphere Machine SSL 证书Ⅳ—— 替换默认证书
目录 博文摘要6. 使用企业 CA 签发的 SSL 证书 替换 vSphere 默认 SSL 证书6.1 确认证书文件6.2 替换默认 vSphere 证书6.3 验证自签名证书6.4 补充说明 关联博文参考资料 博文摘要 博文主要描述了在 vCenter Server 8 上通过实用工具 certificate-manager 将 vSphere 默认 Ma…...

NI9234 4 通道, ±5 V, 24 位软件可选 IEPE 和 AC/DC模拟输入模块振动测试国产替代
NI的自动化测试和测量系统将助您打破桎梏,化不可能为可能。让我们携手合作,选择最适合您的硬件、软件和服务组合,为您提供全副武装,助您成就非凡。 购买NI的产品或服务,并非只是单纯的一次性交易行为。如果您有任何疑…...

宁波市:做大做强跨境电商 赋能外贸创新发展
近日,全国政协第十四届常委会第二次会议专题研究“构建新发展格局,推进中国式现代化”议题,市政协主席徐宇宁参加“推动高水平对外开放”专题小组讨论,全国政协副主席蒋作君到会听取发言,国家发改委、商务部相关司局负…...

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造,完美适配AGV和无人叉车。同时,集成以太网与语音合成技术,为各类高级系统(如MES、调度系统、库位管理、立库等)提供高效便捷的语音交互体验。 L…...

循环冗余码校验CRC码 算法步骤+详细实例计算
通信过程:(白话解释) 我们将原始待发送的消息称为 M M M,依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)(意思就是 G ( x ) G(x) G(x) 是已知的)࿰…...

新能源汽车智慧充电桩管理方案:新能源充电桩散热问题及消防安全监管方案
随着新能源汽车的快速普及,充电桩作为核心配套设施,其安全性与可靠性备受关注。然而,在高温、高负荷运行环境下,充电桩的散热问题与消防安全隐患日益凸显,成为制约行业发展的关键瓶颈。 如何通过智慧化管理手段优化散…...

BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践
6月5日,2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席,并作《智能体在安全领域的应用实践》主题演讲,分享了在智能体在安全领域的突破性实践。他指出,百度通过将安全能力…...

ArcGIS Pro制作水平横向图例+多级标注
今天介绍下载ArcGIS Pro中如何设置水平横向图例。 之前我们介绍了ArcGIS的横向图例制作:ArcGIS横向、多列图例、顺序重排、符号居中、批量更改图例符号等等(ArcGIS出图图例8大技巧),那这次我们看看ArcGIS Pro如何更加快捷的操作。…...

三分算法与DeepSeek辅助证明是单峰函数
前置 单峰函数有唯一的最大值,最大值左侧的数值严格单调递增,最大值右侧的数值严格单调递减。 单谷函数有唯一的最小值,最小值左侧的数值严格单调递减,最小值右侧的数值严格单调递增。 三分的本质 三分和二分一样都是通过不断缩…...
华为OD最新机试真题-数组组成的最小数字-OD统一考试(B卷)
题目描述 给定一个整型数组,请从该数组中选择3个元素 组成最小数字并输出 (如果数组长度小于3,则选择数组中所有元素来组成最小数字)。 输入描述 行用半角逗号分割的字符串记录的整型数组,0<数组长度<= 100,0<整数的取值范围<= 10000。 输出描述 由3个元素组成…...
深入解析 ReentrantLock:原理、公平锁与非公平锁的较量
ReentrantLock 是 Java 中 java.util.concurrent.locks 包下的一个重要类,用于实现线程同步,支持可重入性,并且可以选择公平锁或非公平锁的实现方式。下面将详细介绍 ReentrantLock 的实现原理以及公平锁和非公平锁的区别。 ReentrantLock 实现原理 基本架构 ReentrantLo…...

Ray框架:分布式AI训练与调参实践
Ray框架:分布式AI训练与调参实践 系统化学习人工智能网站(收藏):https://www.captainbed.cn/flu 文章目录 Ray框架:分布式AI训练与调参实践摘要引言框架架构解析1. 核心组件设计2. 关键技术实现2.1 动态资源调度2.2 …...

从数据报表到决策大脑:AI重构电商决策链条
在传统电商运营中,决策链条往往止步于“数据报表层”:BI工具整合历史数据,生成滞后一周甚至更久的销售分析,运营团队凭经验预判需求。当爆款突然断货、促销库存积压时,企业才惊觉标准化BI的决策时差正成为增长瓶颈。 一…...