C++设计模式行为型之观察者模式

news/2025/3/12 12:19:03/

一、概述

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

二、示例代码

#include <list>

class Subject;

class Observer
{
public:
    virtual ~Observer();
    virtual void Update(Subject* theChangedSubject) = 0;
protected:
    Observer();
};

class Subject
{
public:
    virtual ~Subject(){}
    virtual void Attach(Observer* o)
    {
        _observers->push_back(o);
    }
    virtual void Detach(Observer* o)
    {
        _observers->remove(o);
    }
    virtual void Notity()
    {
        std::list<Observer*>::iterator it = _observers->begin();
        while (it != _observers->end())
        {
            (*it)->Update(this);
            ++it;
        }
    }
protected:
    Subject();
private:
    std::list<Observer*> *_observers;
};

上述代码是一个简单的观察者设计模式代码,逻辑清晰,但这种不能够通用,只能对特定的观察者才有效,即必须是Observer抽象类的派生类才行,并且这个观察者还不能带参数,而且接口参数不支持变化,那么观察者将不能应付接口的变化。那么应该如何解决这个问题呢?可以使用C++11一些特性来改变。

class NonCopyable
{
protected:
    NonCopyable() = default;
    ~NonCopyable() = default;
    NonCopyable(const NonCopyable&) = delete; //禁用拷贝构造
    NonCopyable& operator = (const NonCopyable&) = delete; //禁用赋值构造
};

#include <iostream>
#include <string>
#include <functional>
#include <map>

using namespace std;

template<typename Func>
class Events : NonCopyable
{
public:
    Events(){}
    ~Events(){}
    //注册观察者,支持右值
    int Connect(Func&& f)
    {
        return Assgin(f);
    }
    //注册观察者
    int Connect(Func& f)
    {
        return Assgin(f);
    }
    //移除观察者
    void Disconnect(int key)
    {
        m_connections.erase(key);
    }
private:
    //保存观察者并分配观察者编号
    template<typename F>
    int Assgin(F&& f)
    {
        int k = m_observerId++;
        m_connections.emplace(k, std::forward<F> (f));
    }
    int m_observerId = 0;
    std::map<int, Func> m_connections;
};

C++11实现的观察者,内部为了一个泛型函数列表,观察者只需要将观察者函数进行注册进来即可,消除了继承导致的强耦合。通知接口使用了可变参数模板,支持任意参数,这就消除了接口变化的影响。


http://www.ppmy.cn/news/1005315.html

相关文章

学了一个礼拜 JavaScript 为什么还是学不会?

前言 首先从你的描述里面我先以我的主观臆断来猜测一下你是没有任何编程的基础的&#xff0c;Js按理来说在各语言中并不是非常难学&#xff0c;当然如果你是纯新手入门&#xff0c;那么确实前期需要时间来沉淀一下语法&#xff0c;一个礼拜的话&#xff0c;按理来说应该是在沉…

新手Vite打包工具的使用并解决yarn create vite报错

一、手动创建 1.创建vite-Demo文件夹 2.初始化 yarn init -y 3.安装vite yarn add -D vite 4.打包准备 说明&#xff1a;不需要在src下面创建&#xff0c;在vite-Demo文件夹创建 4.1index.js文件 document.body.insertAdjacentHTML("beforeend","<h1>…

2500、删除每行中最大值在IDEA中调试Java

leetcode:2500、删除每行中最大值在IDEA中调试&#xff0c;使用Java实现 题目描述&#xff1a; 给你一个 m x n 大小的矩阵 grid &#xff0c;由若干正整数组成。 执行下述操作&#xff0c;直到 grid 变为空矩阵&#xff1a; 从每一行删除值最大的元素。如果存在多个这样的…

七、Spring 面向切面编程(AOP)学习总结

文章目录 一、初识面向切面编程&#xff08;AOP&#xff09;1.1 什么是 AOP1.2 AOP的应用场景1.3 Aop 在 Spring 中的作用1.3.1 Aop 的核心概念 1.4 使用 Spring 实现 AOP1.4.1 方式一&#xff1a;使用 Spring API 接口实现 AOP 【主要是SpringAPI接口实现】1.4.2 方式二&#…

Vue3文本省略(Ellipsis)

APIs 参数说明类型默认值必传maxWidth文本最大宽度number | string‘100%’falseline最大行数numberundefinedfalseexpand是否启用点击文本展开全部booleanfalsefalsetooltip是否启用文本提示框booleantruefalsetooltipMaxWidth提示框内容最大宽度&#xff0c;单位px&#xff…

新手指南:流程图中各种图形的含义及用法解析

我们经常在技术设计、沟通、业务演示等一些领域看到流程图&#xff0c;它也可以称为输入输出图。顾名思义&#xff0c;它是指一种简单的工作流程的具体步骤&#xff0c;比如包括一次会议的流程&#xff0c;以及一次生产制造的顺序和过程等。本文将为大家介绍流程图的含义和具体…

用Rust实现23种设计模式之单例

话不多说&#xff0c;上代码&#xff01; 1. 使用Arc Mutex 在这个例子中&#xff0c;我们使用了 Arc &#xff08;原子引用计数&#xff09;和 Mutex &#xff08;互斥锁&#xff09;来实现线程安全的单例。通过 get_instance 方法&#xff0c;我们可以获取到单例实例&…

如何分辨几类网线 如何制作网线的工作笔记

如何分辨几类网线 方法一. 可以通过查看网线的皮胶套上的数字进行判断 方法二. 1、六类网线和五类网线的内部结构不同&#xff0c;六类网线内部结构增加了十字骨架&#xff0c;将双绞线的四对线缆分别置于十字骨架的四个凹槽内&#xff0c;电缆中央的十字骨架随长度的变化而…