设计模式:观察者模式(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的产品或服务,并非只是单纯的一次性交易行为。如果您有任何疑…...
宁波市:做大做强跨境电商 赋能外贸创新发展
近日,全国政协第十四届常委会第二次会议专题研究“构建新发展格局,推进中国式现代化”议题,市政协主席徐宇宁参加“推动高水平对外开放”专题小组讨论,全国政协副主席蒋作君到会听取发言,国家发改委、商务部相关司局负…...
Linux应用开发之网络套接字编程(实例篇)
服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …...
深度学习在微纳光子学中的应用
深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向: 逆向设计 通过神经网络快速预测微纳结构的光学响应,替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…...
智慧医疗能源事业线深度画像分析(上)
引言 医疗行业作为现代社会的关键基础设施,其能源消耗与环境影响正日益受到关注。随着全球"双碳"目标的推进和可持续发展理念的深入,智慧医疗能源事业线应运而生,致力于通过创新技术与管理方案,重构医疗领域的能源使用模式。这一事业线融合了能源管理、可持续发…...
C++:std::is_convertible
C++标志库中提供is_convertible,可以测试一种类型是否可以转换为另一只类型: template <class From, class To> struct is_convertible; 使用举例: #include <iostream> #include <string>using namespace std;struct A { }; struct B : A { };int main…...
Xshell远程连接Kali(默认 | 私钥)Note版
前言:xshell远程连接,私钥连接和常规默认连接 任务一 开启ssh服务 service ssh status //查看ssh服务状态 service ssh start //开启ssh服务 update-rc.d ssh enable //开启自启动ssh服务 任务二 修改配置文件 vi /etc/ssh/ssh_config //第一…...
django filter 统计数量 按属性去重
在Django中,如果你想要根据某个属性对查询集进行去重并统计数量,你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求: 方法1:使用annotate()和Count 假设你有一个模型Item,并且你想…...
五年级数学知识边界总结思考-下册
目录 一、背景二、过程1.观察物体小学五年级下册“观察物体”知识点详解:由来、作用与意义**一、知识点核心内容****二、知识点的由来:从生活实践到数学抽象****三、知识的作用:解决实际问题的工具****四、学习的意义:培养核心素养…...
基于数字孪生的水厂可视化平台建设:架构与实践
分享大纲: 1、数字孪生水厂可视化平台建设背景 2、数字孪生水厂可视化平台建设架构 3、数字孪生水厂可视化平台建设成效 近几年,数字孪生水厂的建设开展的如火如荼。作为提升水厂管理效率、优化资源的调度手段,基于数字孪生的水厂可视化平台的…...
k8s业务程序联调工具-KtConnect
概述 原理 工具作用是建立了一个从本地到集群的单向VPN,根据VPN原理,打通两个内网必然需要借助一个公共中继节点,ktconnect工具巧妙的利用k8s原生的portforward能力,简化了建立连接的过程,apiserver间接起到了中继节…...
MySQL 主从同步异常处理
阅读原文:https://www.xiaozaoshu.top/articles/mysql-m-s-update-pk MySQL 做双主,遇到的这个错误: Could not execute Update_rows event on table ... Error_code: 1032是 MySQL 主从复制时的经典错误之一,通常表示ÿ…...
