当前位置: 首页 > news >正文

4. 观察者模式

目录

  • 一、现实应用场景
  • 二、初步实现
    • 2.1 实现方案1
    • 2.2 实现方案2
  • 三、观察者模式
    • 3.1 应用场景
    • 3.2 详解
    • 3.3 实现
    • 3.4 设计类图
  • 四、实现

一、现实应用场景

  1. 教师的手机号改变之后要通知给所有学生
  2. 如果有一个学生没有通知到位就会产生遗漏
  3. 如何自动完成

二、初步实现

2.1 实现方案1

  • 定义学生和教师类
  • 教师类设置set和get方法
  • 教师的手机号修改后要依次调用所有学生的类重新设置
#include <iostream>class Student
{
private:std::string m_name;std::string m_tPhone;public:Student(const std::string& name){m_name = name;}void setTPhoneNubmer(const std::string& phone){m_tPhone = phone;}void show(){std::cout << "Name: " << m_name << " Teacher's Phone: " << m_tPhone << std::endl;}
};class Teacher
{
private:std::string m_phone;public:Teacher(const std::string& phone){m_phone = phone;}void setPhone(const std::string& phone){m_phone = phone;}std::string getPhone() const {return m_phone;}
};int main()
{Teacher zwz("12345");Student li("LiLei");Student Jie("Jie");Student wcz("wcz");li.setTPhoneNubmer(zwz.getPhone());Jie.setTPhoneNubmer(zwz.getPhone());wcz.setTPhoneNubmer(zwz.getPhone());li.show();Jie.show();wcz.show();//修改zwz.setPhone("67890");li.setTPhoneNubmer(zwz.getPhone());Jie.setTPhoneNubmer(zwz.getPhone());wcz.setTPhoneNubmer(zwz.getPhone());li.show();Jie.show();wcz.show();return 0;
}

2.2 实现方案2

  • 学生类中拥有一个教师的实例,该实例由外部传入
  • 只要教师的手机号在外部修改,那个学生类中只需要通过getPhone()函数即可得到教师的手机号
  • 实现过程如下
#include <iostream>class Teacher
{
private:std::string m_phone;public:Teacher(const std::string& phone){m_phone = phone;}void setPhone(const std::string& phone){m_phone = phone;}std::string getPhone() const{return m_phone;}
};class Student
{
private:std::string m_name;std::string m_tPhone;const Teacher* m_teacher;public:Student(const std::string& name, const Teacher* teacher){m_name = name;m_teacher = teacher;}void show(){std::cout << "Name: " << m_name << " Teacher's Phone: " << m_teacher->getPhone() << std::endl;}
};int main()
{Teacher zwz("12345");Student li("LiLei", &zwz);Student Jie("Jie", &zwz);Student wcz("wcz", &zwz);li.show();Jie.show();wcz.show();//修改zwz.setPhone("67890");li.show();Jie.show();wcz.show();return 0;
}
  • 存在问题
    • 两个对象间存在紧耦合关系
    • 如果换老师之后,老师的实例还得修改
    • 缺少扩展性与灵活性

三、观察者模式

3.1 应用场景

  • 当对象发生变化,通知给其他对象,需要其他对象做出调整
  • 应用程序的可维护性和重用性较高
  • 互动关系不能体现成类之间的直接调用,对象之间关系的解耦

3.2 详解

  • 观察者模式又称为发布订阅模式
  • 两个角色: 观察者和被观察对象
  • 两者之间存在”观察“的逻辑关联
  • 当被观察者发生改变的时候,观察者就会观察到这样的变化,并且做出相应的响应
  • 观察不是直接调用
  • 实现观察者模式有很多形式,比较直观的一种是注册-> 通知 -> 撤销注册形式。

3.3 实现

  1. 步骤1:观察者将自己注册到被观察对象中,被观察对象将观察者存放在一个容器中。
  2. 步骤2:被观察者对象发生了某种变化,从容器中得到所有注册过的观察者,将变化通知观察者。
  3. 步骤3(可选):观察者告诉被观察者要撤销观察,被观察者从容器中将观察者去除。

3.4 设计类图

在这里插入图片描述

  • ConcreteSubject:
    • 主题对象,被观察者,对应老师。
    • 他有变化时通知ConcreteObserver类的实例(学生)。学生根据变化自动调用update()做出响应。
    • 内部有一个队列存储、移除观察者
    • 当状态发生变化时可以调用notifyObservers()通知观察者
  • ConcreteSubjectConcreteObserver类解耦
    • 学生不只可以观察老师,还可以观察学院、某个同学等。
    • 两个类分别向上抽取了被观察者接口 (Subject)和观察者接口(Observer)

四、实现

#include <iostream>
#include <list>class IObserver
{
public:virtual void update(void* o) = 0;
};class ISubject
{
public:virtual void registerObserver(IObserver* obj) = 0;virtual void removeObserver(IObserver* obj) = 0;virtual void notifyObserver() = 0;
};class Teacher: ISubject
{
private:std::string m_phone;std::list<IObserver*> m_subject;public:void setPhone(const std::string& phone){m_phone = phone;notifyObserver();}std::string getPhone() const{return m_phone;}void registerObserver(IObserver* o){m_subject.push_back(o);}void removeObserver(IObserver* o){m_subject.remove(o);}void notifyObserver(){for (auto item : m_subject){item->update((void*)m_phone.c_str());}}
};class Student: public IObserver
{
private:std::string m_name;std::string m_tPhone;public:Student(const std::string& name){m_name = name;}void update(void* o){m_tPhone = reinterpret_cast<char*>(o);}void show(){std::cout << "Name: " << m_name << " Teacher's Phone: " << m_tPhone << std::endl;}
};int main()
{Teacher zwz;Student li("LiLei");Student Jie("Jie");Student wcz("wcz");Student test("test");zwz.registerObserver(&li);zwz.registerObserver(&Jie);zwz.registerObserver(&wcz);std::cout << "\n*******设置教师手机号为12345*******" << std::endl;zwz.setPhone("12345");li.show();Jie.show();wcz.show();zwz.removeObserver(&wcz); //移除对wcz的通知std::cout << "\n*******对教师手机号进行修改为67890*******" << std::endl;//修改zwz.setPhone("67890");li.show();Jie.show();std::cout << "\n*******不会被改变*******" << std::endl;wcz.show();  //不会被改变return 0;
}
  • 创建观察者接口IObserver(),并规定了更新的行为。
  • 创建被观察者接口ISubject(),并规定了添加、移除和通知观察者的行为。
  • 运行结果
    在这里插入图片描述
http://www.lryc.cn/news/586637.html

相关文章:

  • Java行为型模式---观察者模式
  • Typecho分类导航栏开发指南:从基础到高级实现
  • 低代码引擎核心技术:OneCode常用动作事件速查手册及注解驱动开发详解
  • Pytorch实现感知器并实现分类动画
  • 深入理解观察者模式:构建松耦合的交互系统
  • 为什么玩游戏用UDP,看网页用TCP?
  • 【C++详解】STL-priority_queue使用与模拟实现,仿函数详解
  • 信息收集实战
  • 【读书笔记】《C++ Software Design》第九章:The Decorator Design Pattern
  • 设计模式:软件开发的高效解决方案(单例、工厂、适配器、代理)
  • 基于无人机 RTK 和 yolov8 的目标定位算法
  • 一文认识并学会c++模板(初阶)
  • AI 助力编程:Cursor Vibe Coding 场景实战演示
  • 基于 Redisson 实现分布式系统下的接口限流
  • 牛客网50题
  • 【C/C++】编译期计算能力概述
  • [Python] -实用技巧篇1-用一行Python代码搞定日常任务
  • python-range函数
  • 校园幸运抽(抽奖系统)测试报告
  • 第七章应用题
  • HT8313功放入门
  • HashMap的原理
  • 数据结构与算法之美:线索二叉树
  • 蒙特卡洛树搜索方法实践
  • 蓝牙调试抓包工具--nRF Connect移动端 使用详细总结
  • 生成式对抗网络(GAN)模型原理概述
  • Java生产带文字、带边框的二维码
  • 牛客:HJ19 简单错误记录[华为机考][字符串]
  • 009 ST表:静态区间最值的极致优化
  • 面试现场:奇哥扮猪吃老虎,RocketMQ高级原理吊打面试官