【观察者设计模式详解】C/Java/JS/Go/Python/TS不同语言实现

简介

观察者模式(Observer Pattern)是一种行为型模式。它定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。

观察者模式使用三个类Subject、Observer和Client。Subject对象带有绑定观察者到Client对象和从Client对象解绑观察者的方法。我们创建Subject类、Observer抽象类和扩展了抽象类Observer的实体类。

作用

  1. 一个对象状态更新,其他依赖对象收到通知和自动更新的机制。
  2. 实现模块化分离,实现主题与观察者交互对象之间的松耦合。
    1)观察者定义了对象之间一对多的关系。
    2)被观察者(主题)用一个共同的接口来更新观察者。
    3)观察者和被观察者用松耦合方式结合,被观察者不知道观察者的细节,只知道观察者实现了观察者接口。

实现步骤

  1. 创建观察者observer基础接口,包含主题和更新方法
  2. 创建主题subject抽象类,包含observer列表以及添加和删除方法
  3. 创建具体的主题类,实现通知方法,发布通知时轮询通知全部观察者
  4. 创建多个具体观察者,与主题关联,并实现自己的更新方法
  5. 客户调用时先声明主题,再将观察者分别添加到主题,当主题发布通知时,观察者自动更新

UML

 

Java代码

观察者接口

 
// ObserverAPI.java 观察者接口,Java 9已经默认支持Observer接口
// 这里避免冲突采取ObserverAPI命名
public interface ObserverAPI {
public Subject subject = null;
public void update(String content);
}

具体观察者

 
// ConcreteObserver.java 具体的观察者实现类,也可以看成订阅者,关联对应的主题类。
// 不同的观察者也可以对应多个主题
public class ConcreteObserver implements ObserverAPI {
public Subject subject;
// 给观察者绑定主题,同时把观察者添加到主题列表
public ConcreteObserver(Subject subject) {
this.subject = subject;
this.subject.register((ObserverAPI) this);
}
// 观察者发出更新通知,不用单独告诉订阅者,由订阅者自行监听
public void update(String content) {
System.out.println(String.format("%s::update() [subject.name = %s content = %s]",
this.getClass().getName(),
this.subject.getName(), content));
}
}

 
// ConcreteObserver2.java 具体的观察者实现类,也可以看成订阅者,关联对应的主题类。
// 不同的观察者可以对应不同的主题。
public class ConcreteObserver2 implements ObserverAPI {
// 这里没有在构造器就绑定某个主题,而是从客户角度去注册观察者
public ConcreteObserver2() {
}
// 观察者发出更新通知,观察者自行监听
public void update(String content) {
System.out.println(String.format("%s::update() [content = %s]",
this.getClass().getName(), content));
}
}

抽象主题类

 
// Subject.java 定义抽象主题类或者接口,供具体主题类继承
public abstract class Subject {
private String name;
// protected Set<ObserverAPI> observers = new HashSet<>();
protected List<ObserverAPI> observers = new ArrayList<>();
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void register(ObserverAPI observer) {
System.out.println(this.getClass().getName() + "::register() [observer = " + observer.getClass().getSimpleName() + "]");
observers.add(observer);
}
public void remove(ObserverAPI observer) {
observers.remove(observer);
}
// 通知由具体类来实现逻辑
public abstract void notify(String name);
}

具体主题类

 
// ConcreteSubject.java 观察者主题类,也是发布者,重写具体的通知方法。不同主题可以关联不同的观察者。
public class ConcreteSubject extends Subject {
public ConcreteSubject(String name) {
this.setName(name);
}
// 不同的主题类有自己的通知方法,批量通知绑定的观察者
@Override
public void notify(String content) {
System.out.println(this.getClass().getName() + "::notify() [content = " + content + "]");
for (Object observer : this.observers) {
((ObserverAPI) observer).update(content);
}
}
}

测试调用

 
/**
* 观察者模式应用非常广泛,主要是观察者提前绑定到发布者
* 当发布者发布消息时,批量广播通知,而无需逐一通知
* 观察者监听到消息后自己决定采取哪一种行为
*/
// 定义一个主题,也就是发布者
Subject concreteSubject = new ConcreteSubject("subject1");
// 再声明观察者,通过构造器注册到主题上
ObserverAPI observer1 = new ConcreteObserver(concreteSubject);
// 也可以单独给主题注册一个新的观察者
concreteSubject.register(new ConcreteObserver2());
// 可以移除观察者对象,可以打开注释试下
// concreteSubject.remove(observer1);
// 主题开始发布新通知,各观察者自动更新
concreteSubject.notify("hello, this is broadcast.");

Python代码

观察者接口

 
# ObserverAPI.py 观察者抽象父类,定义一些公共方法
class ObserverAPI:
def __init__(self, name):
self.name = name
# 观察者发出更新通知,观察者自行监听
def update(self, content):
print(self.__class__.__name__ + '::update() [content = ' + content + ']')
def set_name(self, name):
self.name = name

具体观察者

 
# ConcreteObserver.py 具体的观察者实现类,也可以看成订阅者,关联对应的主题类。
# 不同的观察者也可以对应多个主题
from src.ObserverAPI import ObserverAPI
# 具体的观察者实现类,也可以看成订阅者,关联对应的主题类。
# 不同的观察者也可以对应多个主题
class ConcreteObserver(ObserverAPI):
# 给观察者绑定主题,同时把观察者添加到主题列表
def __init__(self, subject, name):
ObserverAPI.__init__(self, name)
# python3支持的父类调用
# super(ConcreteObserver, self).__init__(name)
# super().__init__(name)
self.subject = subject
subject.register(self)
# 观察者发出更新通知,不用单独告诉订阅者,由订阅者自行监听
def update(self, content):
print(self.__class__.__name__ + '::update() [subject.name = ' +
self.subject.name + ' content = ' + content + ']')

 
# ConcreteObserver2.py 具体的观察者实现类,也可以看成订阅者,关联对应的主题类。
# 不同的观察者可以对应不同的主题。
from src.ObserverAPI import ObserverAPI
# 具体的观察者实现类,也可以看成订阅者,关联对应的主题类。
# 不同的观察者可以对应不同的主题。
class ConcreteObserver2(ObserverAPI):
# 这里没有在构造器就绑定某个主题,而是从客户角度去注册观察者
# 观察者发出更新通知,观察者自行监听
# def update(self, content):
# print(self.__class__.__name__ + '::update() [content = ' + content +']')
pass

抽象主题类

 
# Subject.py 定义抽象主题类或者接口,供具体主题类继承
class Subject:
def __init__(self, name):
self.name = name
self.observers = []
def get_name(self):
return self.name
def set_name(self, name):
self.name = name
def register(self, observer):
print(self.__class__.__name__ + '::register() [observer = ' +
observer.__class__.__name__ + ']')
self.observers.append(observer)
def remove(self, observer):
self.observers.remove(observer)
# 通知由具体类来实现逻辑
def notify(self, name):
pass

具体主题类

 
// ConcreteSubject.py 观察者主题类,也是发布者,重写具体的通知方法。不同主题可以关联不同的观察者。
from src.Subject import Subject
# 观察者主题类,也是发布者,重写具体的通知方法。不同主题可以关联不同的观察者。
class ConcreteSubject(Subject):
# 不同的主题类有自己的通知方法,批量通知绑定的观察者
def notify(self, content):
print(self.__class__.__name__ + '::notify() [content = ' + content +
']')
for observer in self.observers:
observer.update(content)

测试调用

 
import sys
import os
os_path = os.getcwd()
sys.path.append(os_path)
from src.ConcreteSubject import ConcreteSubject
from src.ConcreteObserver import ConcreteObserver
from src.ConcreteObserver2 import ConcreteObserver2
def test():
'''
* 观察者模式应用非常广泛,主要是观察者提前绑定到发布者
* 当发布者发布消息时,批量广播通知,而无需逐一通知
* 观察者监听到消息后自己决定采取哪一种行为
'''
# 定义一个主题,也就是发布者
concrete_subject = ConcreteSubject('subject1')
# 再声明观察者,通过构造器注册到主题上
observer1 = ConcreteObserver(concrete_subject, 'observer1')
# 也可以单独给主题注册一个新的观察者
observer2 = ConcreteObserver2('observer2')
concrete_subject.register(observer2)
# 可以移除观察者对象
# concrete_subject.remove(observer1)
# 主题开始发布新通知,各观察者自动更新
concrete_subject.notify('hello, this is broadcast.')
if __name__ == '__main__':
print(__file__)
print("test start:")
test()

更多语言版本

不同语言实现设计模式:https://github.com/microwind/design-pattern

  

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/88014.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

opencv 基础50-图像轮廓学习03-Hu矩函数介绍及示例-cv2.HuMoments()

什么是Hu 矩&#xff1f; Hu 矩&#xff08;Hu Moments&#xff09;是由计算机视觉领域的科学家Ming-Kuei Hu于1962年提出的一种图像特征描述方法。这些矩是用于描述图像形状和几何特征的不变特征&#xff0c;具有平移、旋转和尺度不变性&#xff0c;适用于图像识别、匹配和形状…

JDK 8 升级 JDK 17 全流程教学指南

JDK 8 升级 JDK 17 首先已有项目升级是会经历一个较长的调试和自测过程来保证允许和兼容没有问题。先说几个重要的点 遇到问题别放弃仔细阅读报错&#xff0c;精确到每个单词每一行&#xff0c;不是自己项目的代码也要点进去看看源码到底是为啥报错明确你项目引入的包&#x…

设计模式之简单工厂模式

一、概述 定义一个用于创建对象的接口&#xff0c;让子类决定实例化哪一个类。工厂模式使一个类的实例化延迟到其子类。 简单工厂模式&#xff1a;又叫做静态工厂方法模式&#xff0c;是由一个工厂对象决定创建出哪一种产品类的实例。 二、适用性 1.当一个类不知道它所必须…

Microsoft SQL Server 2008中,语法生成错误“并行数据仓库(PDW)功能未启用“(已解决)

案例&#xff1a; 原表有两列&#xff0c;分别为月份、月份销售额&#xff0c;而需要一条 SQL 语句实现统计出每个月份以及当前月以前月份销售额和 sql 测试数据准备&#xff1a; DECLARE Temp Table ( monthNo INT, --- 月份 MoneyData Float --- 金额 ) insert INTO TEM…

1.阿里云对象存储OSS

1.对象存储概述 文件上传&#xff0c;是指将本地图片、视频、音频等文件上传到服务器上&#xff0c;可以供其他用户浏览或下载的过程。文件上传在项目中应用非常广泛&#xff0c;我们经常发抖音、发朋友圈都用到了文件上传功能。 实现文件上传服务&#xff0c;需要有存储的支持…

变形金刚在图像识别方面比CNN更好吗?

链接到文 — https://arxiv.org/pdf/2010.11929.pdf 一、说明 如今&#xff0c;在自然语言处理&#xff08;NLP&#xff09;任务中&#xff0c;转换器已成为goto架构&#xff08;例如BERT&#xff0c;GPT-3等&#xff09;。另一方面&#xff0c;变压器在计算机视觉任务中的使用…

将tp5项目、fastadmin项目部署到服务器宝塔面板

目录 一、将你的fastadmin或者tp5项目文件夹上传至你的服务器域名根目录下 二、修改你的网站目录指向&#xff0c;指向public目录&#xff0c;点击保存&#xff0c;并取消勾选防跨站攻击。 三、配置伪静态 四、fastadmin框架上传至服务器后如果想要访问后台可以进行重定向&am…

Go Web--Go Module

目录 一、Go Module 1、开启Go Module 2、Go Module基本操作 3、使用GoLand创建Go Module项目 4、GoLand配置File Watchers 一、Go Module Go Module包管理工具----相当于Maven 1.11版本引入 1.12版本正式支持 告别GOPATH&#xff0c;使用Go Module管理项目&#xff0c…

linux中的ifconfig和ip addr

在linux操作系统中ifconfig和ip addr都是显示网卡配置信息的命令&#xff0c;好多人有疑惑它们有什么区别呢 区别1&#xff1a;对于linux发行的版本不一样 ip addr是对新发行版本的linux使用会比较多&#xff1b;而ifconfig是老版本遇到使用的会比较多。 区别2&#xff1a;显…

LeetCode150道面试经典题--单词规律(简单)

1.题目 给定一种规律 pattern 和一个字符串 s &#xff0c;判断 s 是否遵循相同的规律。 这里的 遵循 指完全匹配&#xff0c;例如&#xff0c; pattern 里的每个字母和字符串 s 中的每个非空单词之间存在着双向连接的对应规律。 2.示例 pattern"abba" s "c…

springboot中消失的静态资源

springboot中消失的静态资源 问题&#xff1a;springboot项目中&#xff0c;resource/static 目录下的index.html以及template目录下 。实现WebMvcConfigurer这个接口&#xff0c;index.html就404了。 原因&#xff1a;实现了 WebMvcConfigurer 接口后&#xff0c;index.html …

日常BUG——通过命令行创建vue项目报错

&#x1f61c;作 者&#xff1a;是江迪呀✒️本文关键词&#xff1a;日常BUG、BUG、问题分析☀️每日 一言 &#xff1a;存在错误说明你在进步&#xff01; 一、问题描述 在使用vue命令行创建一个vue项目时&#xff0c;出现一下的错误&#xff1a; vue create my…

Leetcode33 搜索旋转排序数组

题解&#xff1a; /*** 旋转排序数组可分为N1 N2两个部分&#xff0c;如&#xff1a;[4,5,6,7,1,2,3]&#xff0c;N1为[4,5,6,7]&#xff0c;N2为[1,2,3]** 必然满足以下两个条件&#xff1a;* 1. N1和N2都是分别递增的&#xff1b;* 2. N1中的所有元素大于N2中的所有元素;** …

机器学习、深度学习项目开发业务数据场景梳理汇总记录二

本文的主要作用是对历史项目开发过程中接触到的业务数据进行整体的汇总梳理&#xff0c;文章会随着项目的开发推进不断更新。 这里是续文&#xff0c;因为CSDN单篇文章内容太大的话就会崩溃的&#xff0c;别问我怎么知道的&#xff0c;问就是血泪教训&#xff0c;辛辛苦苦写了一…

Linux安装JDK

1、到Oracle官网下载JDK https://www.oracle.com/java/technologies/downloads/#java8 Oracle账号可以网上搜或者自己注册一个&#xff0c;JDK安装包根据Linux版本自行选择&#xff0c;我的Linux系统是64位的&#xff0c;所以我这里选择的是x64的JDK安装包 2、下载完后把JDK上…

10-1_Qt 5.9 C++开发指南_Data Visualization实现数据三维显示

Data Visualization 是 Qt 提供的用于数据三维显示的模块。在 Qt 5.7 以前只有商业版才有此模块&#xff0c;而从Qt5.7 开始此模块在社区版本里也可以免费使用了。Data Visualization 用于数据的三维显示&#xff0c;包括三维柱状图、三维空间散点、三维曲面等。Data Visualiza…

【Spring专题】Spring之底层架构核心概念解析

目录 前言前置知识课程内容一、BeanDefinition&#xff1a;图纸二、BeanDefinitionReader&#xff1a;图纸注册器——Spring工厂基础设施之一2.1 AnnotatedBeanDefinitionReader2.2 XmlBeanDefinitionReader2.3 ClassPathBeanDefinitionScanner基本介绍总结使用示例 三、BeanFa…

MD-MTSP:光谱优化算法LSO求解多仓库多旅行商问题MATLAB(可更改数据集,旅行商的数量和起点)

一、光谱优化算法LSO 光谱优化算法&#xff08;Light Spectrum Optimizer&#xff0c;LSO&#xff09;由Mohamed Abdel-Basset等人于2022年提出。 参考文献&#xff1a; [1]Abdel-Basset M, Mohamed R, Sallam KM, Chakrabortty RK. Light Spectrum Optimizer: A Novel Physi…

msvcr120.dll丢失怎样修复?总结三个dll修复方法

当我遇到msvcr120.dll丢失的问题时&#xff0c;我感到有些困惑和焦虑。因为这个问题会导致我无法运行依赖这个文件的应用程序。msvcr120.dll是运行时库文件的一部分&#xff0c;为应用程序提供了必要的运行时支持。它的丢失会导致应用程序无法正常运行&#xff0c;这让我意识到…

elementui实现当前页全选+所有全选+翻页保持选中状

原文来自&#xff1a;https://blog.csdn.net/sumimg/article/details/121693305?spm1001.2101.3001.6650.1&utm_mediumdistribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1-121693305-blog-127570059.235%5Ev38%5Epc_relevant_anti_t3&depth_1-utm…