C++ 设计模式之观察者模式

【声明】本题目来源于卡码网(题目页面 (kamacoder.com))

【提示:如果不想看文字介绍,可以直接跳转到C++编码部分】


【设计模式大纲】

         前面的文章介绍了创建型模式和结构型模式,今天开始介绍行为型模式。


【简介】什么是观察者模式(第13种模式)

        观察者模式(发布-订阅模式)属于⾏为型模式,定义了⼀种⼀对多的依赖关系,让多个观察者对象同时监听⼀个主题对象,当主题对象的状态发⽣变化时,所有依赖于它的观察者都得到通知并被⾃动更新。
        观察者模式依赖两个模块:

  • Subject (主题):也就是被观察的对象,它可以维护⼀组观察者,当主题本身发⽣改变时就会通知观察者。
  • Observer (观察者):观察主题的对象,当“被观察”的主题发⽣变化时,观察者就会得到通知并执⾏相应的处理。

 

        使⽤观察者模式有很多好处,⽐如说观察者模式将主题和观察者之间的关系解耦,主题只需要关注⾃⼰的状态变化,⽽观察者只需要关注在主题状态变化时需要执⾏的操作,两者互不⼲扰,并且由于观察者和主题是相互独⽴的,可以轻松的增加和删除观察者,这样实现的系统更容易扩展和维护。


【基本结构】

        观察者模式依赖主题和观察者,但是⼀般有4个组成部分:

  •  主题Subject : ⼀般会定义成⼀个接⼝,提供⽅法⽤于注册、删除和通知观察者,通常也包含⼀个状态,当状态发⽣改变时,通知所有的观察者。
  • 观察者Observer : 观察者也需要实现⼀个接⼝,包含⼀个更新⽅法,在接收主题通知时执⾏对应的操作。
  • 具体主题ConcreteSubject : 主题的具体实现, 维护⼀个观察者列表,包含了观察者的注册、删除和通知⽅法。
  • 具体观察者ConcreteObserver : 观察者接⼝的具体实现,每个具体观察者都注册到具体主题中,当主题状态变化并通知到具体观察者,具体观察者进⾏处理。

 【基本实现】

        根据上⾯的类图,我们可以写出观察者模式的基本实现(以Java代码作以说明):

1. 主题接口

// 主题接⼝ (主题)
interface Subject {// 注册观察者void registerObserver(Observer observer);// 移除观察者void removeObserver(Observer observer);// 通知观察者void notifyObservers();
}

2. 观察者接口

// 观察者接⼝ (观察者)
interface Observer {// 更新⽅法void update(String message);
}

3. 具体主题的实现

// 具体主题实现
class ConcreteSubject implements Subject {// 观察者列表private List<Observer> observers = new ArrayList<>();// 状态private String state;// 注册观察者@Overridepublic void registerObserver(Observer observer) {observers.add(observer);}// 移除观察者@Overridepublic void removeObserver(Observer observer) {observers.remove(observer);}// 通知观察者@Overridepublic void notifyObservers() {for (Observer observer : observers) {// 观察者根据传递的信息进⾏处理observer.update(state);}}// 更新状态public void setState(String state) {this.state = state;notifyObservers();}
}

4. 具体观察者的实现

// 具体观察者实现
class ConcreteObserver implements Observer {// 更新⽅法@Overridepublic void update(String message) {}
}

【使用场景】

        观察者模式特别适⽤于⼀个对象的状态变化会影响到其他对象,并且希望这些对象在状态变化时能够⾃动更新的情况。 ⽐如说在图形⽤户界⾯中,按钮、滑动条等组件的状态变化可能需要通知其他组件更新,这使得观察者模式被⼴泛应⽤于GUI框架,⽐如Java的Swing框架。
        此外,观察者模式在前端开发和分布式系统中也有应⽤,⽐较典型的例⼦是前端框架Vue , 当数据发⽣变化时,视图会⾃动更新。⽽在分布式系统中,观察者模式可以⽤于实现节点之间的消息通知机制,节点的状态变化将通知其他相关节点。


【编码部分】

1. 题目描述

        小明所在的学校有一个时钟(主题),每到整点时,它就会通知所有的学生(观察者)当前的时间,请你使用观察者模式实现这个时钟通知系统。

        注意点:时间从 0 开始,并每隔一个小时更新一次。

2. 输入描述

        输入的第一行是一个整数 N(1 ≤ N ≤ 20),表示学生的数量。 接下来的 N 行,每行包含一个字符串,表示学生的姓名。 最后一行是一个整数,表示时钟更新的次数。

3. 输出描述

        对于每一次时钟更新,输出每个学生的姓名和当前的时间。

4. C++编码实例

/**
* @version Copyright (c) 2024 NCDC, Servo。 Unpublished - All rights reserved
* @file ObserverMode.hpp
* @brief 观察者模式
* @autor 写代码的小恐龙er
* @date 2024/01/15
*/#include <iostream>
#include <string>
#include <vector>using namespace std;// 前置声明// 观察者接口类(再次声明 接口类都是属于基类  需要后续具体实现类来重载操作)
class Observer;
// 主题接口
class Subject;
// 具体主题的实现 -- 时钟
class Clock;
// 具体的观察者 -- 学生
class Student;// 观察者接口类
class Observer
{
// 接口函数 -- 更新主题的变化
public:Observer(){}virtual void UpdateTime(int hour) = 0;
};// 主题接口
class Subject
{
// 主题对观察者的接口函数
public:Subject(){}// 注册(添加)观察者virtual void AddObserver(Observer *observer) = 0;// 移除观察者virtual void RemoveObserver(Observer *observer) = 0;// 通知所有观察者virtual void NotifyObservers() = 0;
};// 具体主题的实现 -- 时钟
class Clock : public Subject
{
// 成员数据
private:std::vector<Observer *> _observers;int hourTime = 0;// 成员函数
public:// 重载添加函数void AddObserver(Observer *observer) override {this->_observers.push_back(observer);}// 重载移除函数void RemoveObserver(Observer *observer) override{for(unsigned int i = 0; i < _observers.size(); i++){if(this->_observers[i] == observer){delete this->_observers[i];this->_observers[i] = nullptr;}}}// 重载通知函数void NotifyObservers() override{for(Observer *observer : this->_observers){observer->UpdateTime(this->hourTime);}}// 模拟时间的推移void TimeRun(){this->hourTime = (this->hourTime + 1);NotifyObservers();}};// 具体的观察者 -- 学生
class Student : public Observer
{
// 成员数据
private:string _name;// 成员函数 
public:// 重载构造函数 -- 利用学生姓名来具体实例化学生类Student(string name){this->_name = name;}// 重载更新时间函数void UpdateTime(int hour) override {std::cout << _name << " " << hour << endl;}
};// 客户端代码
int main()
{// 学生数量int stuNum = 0;// 输入std::cin >> stuNum;// 创建具体主题 -- 时钟类Clock * clocker = new Clock();// 创建学生类 -- 用基类创建Observer * student = nullptr;// 学生姓名string name = "";// 输入int i = 0;for(i = 0; i < stuNum; i++){std::cin >>  name;// 创建学生student = new Student(name);// 添加学生clocker->AddObserver(student);}// 时钟更新次数int updateNum = 0;// 输入std::cin >> updateNum;for(i = 0; i < updateNum; i++){//  调用时间推移函数clocker->TimeRun();}// 析构if(student != nullptr){delete student;student = nullptr;}delete clocker;clocker = nullptr;return 0;
}


......

To be continued.

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

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

相关文章

第三讲_ArkTS的初识

ArkTS的初识 1. ArkTS的基本组成2. ArkTS自定义组件 1. ArkTS的基本组成 装饰器&#xff1a; 用于装饰类、结构、方法以及变量&#xff0c;并赋予其特殊的含义。自定义组件&#xff1a;可复用的UI单元&#xff0c;可组合其他组件&#xff0c;图示中Component装饰的struct Hello…

Windterm使用总结

Windterm是一款部分开源的终端软件&#xff0c;目前作者又开始更新了&#xff0c;目前最新版本WindTerm 2.6.0 Prerelease 10。下载地址&#xff1a;https://github.com/kingToolbox/WindTerm/releases 自己遇到的使用问题总结如下。 1. telnet登录设备&#xff0c;按退格键无…

python爬虫--网页代码抓取

我回来了。 目录 前言一、爬虫是什么&#xff1f;二、使用步骤代码讲解第一版第二版第三版 总结 前言 爬虫&#xff0c;第一章 一、爬虫是什么&#xff1f; 爬虫是指一种自动化程序&#xff0c;通常被用于互联网上的数据采集。这些程序会模拟人类用户的行为&#xff0c;通过…

归并排序详解

目录 ​&#x1f4a1;基本思想 &#x1f4a1;图文介绍 &#x1f4a1;动图演示 &#x1f4a1;过程解释 &#x1f4a1;代码实现 &#x1f4a1;递归实现 &#x1f4a1;非递归实现 &#x1f4a1;总结 &#x1f4a1;基本思想 归并排序&#xff08;MERGE-SORT&#xff09;是…

SpringBoot——纯注解配置的Spring

1.环境搭建 1.1.创建工程 拷贝ssm工程&#xff1a; 1.2.待改造的问题 我们发现&#xff0c;之所以我们现在离不开xml配置文件&#xff0c;是因为我们有一处很关键的配置&#xff0c;如果他要也能用注解配置&#xff0c;那么我们就可以脱离xml文件了&#xff1a; 1.2.1.jdbc…

HCIA的路由协议

动态路由协议/静态路由协议 路由表的加表规则&#xff1a; 当学习到多条路由条目时&#xff0c;先比较优先级&#xff0c;优先级小&#xff08;优先级大&#xff09;优先加表&#xff0c;如果优先级一致&#xff0c;比较cost值&#xff0c;cost值小的优先加表&#xff0c;如果…

为什么网上很多人都不推荐新手学习C语言?

今日话题&#xff0c;为什么网上很多人都不推荐新手学习C语言&#xff1f;实际情况并非如此。相反&#xff0c;C语言对于新手来说是一门非常适合入门的编程语言。首先&#xff0c;C语言具有较低的学习曲线。新手只需掌握基本的if-else条件语句和for循环结构&#xff0c;就能开始…

工业设备管理系统:助力企业实现数字化转型

随着工业4.0和智能制造的快速发展&#xff0c;数字化转型已成为企业提升竞争力、适应市场变化的必然选择。工业设备管理系统作为数字化转型的关键组成部分&#xff0c;能够为企业提供实时监控、数据分析、预警和远程控制等功能&#xff0c;助力企业实现数字化转型的目标。 一、…

使用 Docker 部署 的WAF: 雷池社区版

Web应用防火墙&#xff08;WAF&#xff09;是保护网站不受恶意攻击的关键组件。 使用 Docker 部署雷池社区版&#xff0c;可以大大简化安全管理工作。 一、WAF 雷池社区版简介 雷池社区版是一种流行的开源 Web 应用防火墙&#xff0c;它提供基本的安全保护&#xff0c;如防止…

ThreadLocalMap为什么用线性探测解决哈希冲突

前言 ThreadLocal 本身不存储值&#xff0c;访问的是当前线程 ThreadLocalMap 里存储的数据副本&#xff0c;实现了线程间的数据隔离。只有当前线程能访问&#xff0c;也就不存在并发访问时的安全问题了。 ThreadLocal 的核心是 ThreadLocalMap&#xff0c;它和 HashMap 不同的…

【数据结构与算法】quicksort快速排序算法大全:快速排序hoare法,快速排序挖坑法,快速排序前后指针法,快速排序优化,快速排序的非递归实现

一、快速排序算法 快速排序使用分治的思想来进行排序&#xff0c;其基本过程如下&#xff1a; 从待排序数组中选择一个元素作为枢轴&#xff08;pivot&#xff09;。将数组分割成两个子数组&#xff0c;使得左侧子数组的元素都小于等于枢轴&#xff0c;右侧子数组的元素都大于…

【C++初阶】第二站:类与对象(上) -- 上部分

前言: C学习的第二站&#xff1a;类和对象(上)文章的上半部分,知识点:面向过程和面向对象初步认识、类的引入、类的定义、类的访问限定符及封装、类的作用域、类的实例化. 目录 面向过程和面向对象初步认识 类的引入 类的定义 类的访问限定符及封装 访问限定符 封装 类的…