C++观察者模式的创新设计(支持同步和异步)

关于设计模式中的观察者模式,首先先来一段gpt
观察者模式是一种行为设计模式,用于建立对象之间的一对多依赖关系,使得当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并自动更新。这种模式也被称为发布-订阅模式。

观察者模式包含以下角色:
Subject(主题):它是被观察的对象。它包含了一个观察者列表,并提供了方法来添加或删除观察者,以及通知观察者状态改变的方法。
Observer(观察者):它定义了一个更新接口,当被观察对象的状态发生变化时被调用。所有的观察者都实现了这个接口,以便在状态发生变化时能够及时得到通知。
ConcreteSubject(具体主题):它是主题的具体实现类,负责维护被观察对象的状态,并在状态发生变化时通知观察者。
ConcreteObserver(具体观察者):它是观察者的具体实现类,负责实现更新接口,以便在接收到主题通知时能够执行相应的操作。

观察者模式的优点包括:
松耦合:观察者模式将主题和观察者之间的关系解耦,使得它们可以相互独立地变化。
可扩展性:可以任意添加或删除观察者,而不影响主题或其他观察者。
灵活性:可以在运行时动态地添加或删除观察者,以满足实际需求。
观察者模式的缺点包括:
可能导致性能问题:当主题有大量观察者时,通知所有观察者可能会影响性能。
可能引起循环引用:如果观察者与主题之间相互引用,可能会导致循环引用的问题。
使用观察者模式可以很好地实现对象之间的解耦,是面向对象设计中常用的一种模式。
在这里插入图片描述

乍一看是不是和SOA很像,我只关心我需要的服务,需要我就去订阅服务,不需要了可以不订阅或者停止订阅
我认为观察者模式最大的优点是实现模块间的解耦,降低代码的耦合度,符合高内聚低耦合的设计思路

但是从网上的简例,存在着以下缺点:
1:每个Subject只有一个主题,那万一有多个主题呢
2:每个Subject发布主题,通知各个具体观察者时,都是同步运行,当主题有大量观察者时,通知所有观察者可能会影响性能,而且每个观察者具体做了什么,是无法预测的,可能有io调用这种延迟大的操作

根据以上的缺点,我基于C++改良了一版观察者模式
先贴代码,每个文件逐一分析

./
├── CMakeLists.txt
├── observer_base.hpp
├── observer_impl.cpp
├── observer_impl.hpp
├── soam_def_type.hpp
├── soam_testcase.cpp
├── soam_testcase.hpp
├── subject_base.hpp
├── subject_impl.cpp
└── subject_impl.hpp

observer_base.hpp
观察者基类,比较简单,只有一个接口
virtual void Notify(soam_server Service_ID,soam_method Method_ID ,soam_data data,soam_len len,soam_timestamp timestamp) = 0;
由被观察者发布topic的时候调用

#ifndef __OBSERVER_BASE__
#define __OBSERVER_BASE__
#include <iostream>
#include "spdlog/spdlog.h"
#include "soam_def_type.hpp"
/**
 * @description: 观察者基类,定义观察者通知接口
 */
using namespace SOAM;
class observer_base
{
public:
    observer_base(void) 
    {
    };
    virtual ~observer_base()
    {
        SPDLOG_INFO("[observer] destrcutor");
    };
    /**
     * @description: 观察者通知接口
     * @param {uint16} Service_ID
     * @param {uint16} Method_ID
     * @param {void*} data
     * @param {uint32} len
     * @return {*}
    virtual void Notify(soam_server Service_ID,soam_method Method_ID ,soam_data data,soam_len len,soam_timestamp timestamp) = 0;
};
#endif //

subject_base.hpp
主要有三个接口:分别对应注册topic,取消注册topic,发布topic
1:virtual void RegisterSuject(soam_method Method_ID,const std::shared_ptr<observer_base>& pobserver) = 0;
2:virtual void UnregisterSuject(soam_method Method_ID,const std::shared_ptr<observer_base>& pobserver) = 0;
3:virtual void Update(soam_method Method_ID ,soam_data data,soam_len len,soam_timestamp timestamp) = 0;

#ifndef __SUBJECT_BASE__
#define __SUBJECT_BASE__

#include <iostream>
#include <map>
#include <list>
#include <memory>

#include "observer_base.hpp"
#include "spdlog/spdlog.h"
#include "soam_def_type.hpp"
/**
 * @description: 被观察者基类,提供服务注册接口,服务注销接口,服务发布接口
 */
class subject_base
{
public:
    subject_base()
    {
        // SPDLOG_INFO("[Subject] constructor");
    };

    virtual ~subject_base()
    {
        SPDLOG_INFO("[Subject] destructor");
    };

    /**
     * @description:被观察者提供的注册接口,供观察者注册 
     * @param {uint16} Method_ID 方法ID
     * @param {const std::shared_ptr<observer_impl>&} 观察者对象指针
     * @return {*}
     */    
    virtual void RegisterSuject(soam_method Method_ID,const std::shared_ptr<observer_base>& pobserver) = 0;

    /**
     * @description:被观察者提供的取消注册接口,供观察者注册  
     * @param {uint16} Method_ID
     * @param {const std::shared_ptr<observer_impl>&} 观察者对象指针
     * @return {*}
     */    
    virtual void UnregisterSuject(soam_method Method_ID,const std::shared_ptr<observer_base>& pobserver) = 0;

    /**
     * @description: 被观察者发布更新数据
     * @param {uint16} Method_ID
     * @param {void*} data
     * @param {uint32} len
     * @return {*}
     * @Date: 2023-09-27 14:38:00
     * @Author: motianjie motianjie@asensing.com
     */    
    virtual void Update(soam_method Method_ID ,soam_data data,soam_len len,soam_timestamp timestamp) = 0; 
};

#endif //

observer_impl.hpp

#ifndef __OBSERVER_IMPL__
#define __OBSERVER_IMPL__
#include <string>
#include "observer_base.hpp"
using namespace SOAM;
/**
 * @description: 观察者实施类,提供观察者实例名称,Notify接口由孙类实现
 */
class observer_impl : public observer_base
{
public:
    explicit observer_impl(soam_name name,callbackfunc observer_callback);
    ~observer_impl();

    void Notify(soam_server Service_ID,soam_method Method_ID ,soam_data data,soam_len len,soam_timestamp timestamp) override;

    observer_impl& operator=(const observer_impl&) = delete;
    observer_impl(const observer_impl&) = delete;
    observer_impl(observer_impl&&) = delete;

private:
    const std::string name_m; //观察者名称
    callbackfunc observer_callback_m;//观察者回调函数,通知子类执行对应逻辑
};
#endif //

observer_impl.cpp
有参构造函数中,需要回调函数,因为实际使用的模块会继承observer_impl,而suject通知只会到observer_impl,所以需要通过回调函数通知到派生类

#include "observer_impl.hpp"
#include "spdlog/spdlog.h"
#include "spdlog/fmt/bin_to_hex.h"
#include <future>
observer_impl::observer_impl(soam_name name,callbackfunc observer_callback):  name_m(name),
                                                                              observer_callback_m(observer_callback)
{
    SPDLOG_INFO("observer[{}] constructor",this->name_m);
}

observer_impl::~observer_impl()
{
    SPDLOG_INFO("[{}] destructor",this->name_m);
}

void observer_impl::Notify(soam_server Service_ID,soam_method Method_ID ,soam_data data,uint32 len,soam_timestamp timestamp)
{
    observer_callback_m(Service_ID,Method_ID,data,len,timestamp);
}

subject_impl.hpp
回到第一个缺点:
1:每个Subject只有一个主题,那万一有多个主题呢
这里改进了Subject持有observer的数据结构,首先用map建立topic和对该topic的感兴趣的observer们
使用了list来管理这些observer们,利用链表的优点,便于插入和删除
std::map<soam_method,std::list<std::weak_ptr<observer_base>>> Soamap_m;
所以针对不同的topic,都可以建立起映射关系
回到第二个缺点:
2:每个Subject发布主题,通知各个具体观察者时,都是同步运行,当主题有大量观察者时,通知所有观察者可能会影响性能,而且每个观察者具体做了什么,是无法预测的,可能有io调用这种延迟大的操作
针对这个缺点,要引入异步发布topic,使用线程池来实现
第二个是构造函数要指明是topic发布时是异步还是同步,如果是同步,实时性会高一点,但是当topic有大量观察者,通知所有观察者可能会影响性能,所以也提供了异步的方式,具体异步是通过将通知observer的任务提交到线程池中处理,这里线程池的实现可以看我另外一篇文章

https://blog.csdn.net/motianjie/article/details/137713148?spm=1001.2014.3001.5502

3: 被观察者持有观察者,为了避免智能指针的循环引用,应该采用弱引用
std::map<soam_method,std::list<std::weak_ptr<observer_base>>> Soamap_m;
std::queue<std::pair<soam_method,std::weak_ptr<observer_base>>> regist_queue;
std::queue<std::pair<soam_method,std::weak_ptr<observer_base>>> unregist_queue;

#ifndef __SUBJECT_IMPL__
#define __SUBJECT_IMPL__
#include "subject_base.hpp"
#include "threadpool.hpp"
#include <mutex>
#include <queue>
class observer_impl;
/**
 * @description: 被观察者实现类
 */
class subject_impl : public subject_base
{
public:
    explicit subject_impl(soam_name name,soam_server Service_ID,soam_method MethoID_Max,subject_launch mode);
    ~subject_impl();

    void RegisterSuject(soam_method Method_ID, const std::shared_ptr<observer_base>& pobserver);

    void UnregisterSuject(soam_method Method_ID,const std::shared_ptr<observer_base>& pobserver);

    void Update(soam_method Method_ID ,soam_data data,soam_len len,soam_timestamp timestamp) override;

    tp_info_t getter_threadpool_info();

    subject_impl& operator=(const subject_impl&) = delete;
    subject_impl(const subject_impl&) = delete;
    subject_impl(subject_impl&&) = delete;
    
private:
    const std::string name_m;
    soam_server Service_ID_m;
    soam_method MethoID_Max_m;
    subject_launch mode_m;//被观察者模式,异步or同步
    std::recursive_mutex register_mut_m;
    std::map<soam_method,std::list<std::weak_ptr<observer_base>>> Soamap_m;

    std::queue<std::pair<soam_method,std::weak_ptr<observer_base>>> regist_queue;
    std::queue<std::pair<soam_method,std::weak_ptr<observer_base>>> unregist_queue;
    static threadpool thread_pool_m;
};
#endif

subject_impl.cpp
1:注册和取消注册,并没有立即对std::map<soam_method,std::list<std::weak_ptr<observer_base>>> Soamap_m;
进行操作,为了是运行过程中,对topic的注册和取消注册可能会导致存储在Soamap_m的observer发生冲突,所以先加入到队列中,等到下次subject发布topic的时候再更新Soamap_m,更新完后再发布
2:发布topic时,如果是异步,则将通知observer的任务提交到线程池,如果是同步,就顺序通知所有的observer
3:因为异步,有可能局部变量出栈了,或者说生命周期已过,会导致发生访问错误内存,所以lambda要采用值捕获,对于普通变量都拷贝一份,对于void*指针,将其封装为shared_ptr

#include "subject_impl.hpp"
#include "observer_impl.hpp"
#include <iostream>
#include <chrono>
#include <future>
#include <cstring>
threadpool subject_impl::thread_pool_m("soam",threadpool_mode::latency);
subject_impl::subject_impl(soam_name name,soam_server Service_ID,soam_method MethoID_Max,subject_launch mode):  name_m(name),
                                                                                                                Service_ID_m(Service_ID),
                                                                                                                MethoID_Max_m(MethoID_Max),
                                                                                                                mode_m(mode)                                                                                                                                                                                              
{
    SPDLOG_INFO("suject[{}] constructor",this->name_m);
}

subject_impl::~subject_impl()
{
    SPDLOG_INFO("[{}] destructor",this->name_m);
}

void subject_impl::RegisterSuject(soam_method Method_ID,const std::shared_ptr<observer_base>& pobserver)
{
    if(MethoID_Max_m <= Method_ID) //注册的方法ID校验,超过可提供的最大方法ID
    {
        SPDLOG_ERROR("Module [{}] register Method_ID [{}] fail Method_ID over range",this->name_m,Method_ID);
        return;
    }

    std::lock_guard<std::recursive_mutex> lock(register_mut_m);

    if(pobserver == nullptr) //注册的观察者为空指针
    {
       SPDLOG_ERROR("Module [{}] register Method_ID [{}] fail date nullptr",this->name_m,Method_ID);
        return;
    }
    
    regist_queue.push({Method_ID,pobserver});
}

void subject_impl::UnregisterSuject(soam_method Method_ID,const std::shared_ptr<observer_base>& pobserver)
{
    if(MethoID_Max_m <= Method_ID) //取消注册的方法ID校验,超过可提供的最大方法ID
    {
      SPDLOG_ERROR("Module [{}] Unregister Method_ID [{}] fail Method_ID over range",this->name_m,Method_ID);
        return;
    }

    std::lock_guard<std::recursive_mutex> lock(register_mut_m);

    if(pobserver == nullptr) //取消注册的观察者为空指针
    {
        SPDLOG_ERROR("Module [{}] Unregister Method_ID [{}] fail date nullptr",this->name_m,Method_ID);
        return;
    }

    unregist_queue.push({Method_ID,pobserver});//加入移除队列,再下一次notify的时候真正移除
}

void subject_impl::Update(soam_method Method_ID ,soam_data data,soam_len len,soam_timestamp timestamp)
{
    if(data == NULL) //发布的数据为空指针
    {
        SPDLOG_ERROR("Module [{}] update Method_ID [{}] fail date nullptr",this->name_m,Method_ID);
        return;
    }

    if(len == 0) //发布的数据长度为0
    {
       SPDLOG_ERROR("Module [{}] update Method_ID [{}] fail len 0",this->name_m,Method_ID);
        return;
    }

    if(Method_ID >= MethoID_Max_m) //发布的方法ID超阈值
    {
       SPDLOG_ERROR("Module [{}] update Method_ID [{}] fail Method_ID over range",this->name_m,Method_ID);
        return;
    }

    std::lock_guard<std::recursive_mutex> lock(register_mut_m); //用递归锁,否则如果用互斥锁在Update中调用Reg or UnReg会导致死锁
    while(!regist_queue.empty())
    {
        auto pobserver = regist_queue.front();
        regist_queue.pop();
        this->Soamap_m[pobserver.first].push_back(pobserver.second);//存入对应方法ID的观察者链表中
    }
    
    while(!unregist_queue.empty())
    {
        auto pobserver = unregist_queue.front();
        if(pobserver.first != Method_ID)//判断当前notify的method id和移除队列中的method id是否一致,一致再移除
        {
            break;   
        }
        unregist_queue.pop();
        this->Soamap_m[pobserver.first].remove_if([&](const std::weak_ptr<observer_base>& o) { return o.lock() == pobserver.second.lock(); });//在对应方法ID的观察者链表中移除
    }
#ifdef DEBUG
    auto starttime = std::chrono::steady_clock::now(); //获取测试代码开始前当前系统时间

#endif
    std::shared_ptr<uint8_t> ptr(new uint8_t[len]);//将普通指针转化为共享指针,防止异步执行任务指针指向错误问题
    std::memcpy(ptr.get(), data, len);
    if(mode_m == subject_launch::ASYNC)
    {
        thread_pool_m.submit([=](){ 
            {   //因为是异步,一定要值捕获,引用捕获变量的生命周期无法管理
                for(auto it : this->Soamap_m[Method_ID])
                {
                    if (auto observerPtr = it.lock())
                    {
                        observerPtr->Notify(Service_ID_m,Method_ID,ptr.get(),len,timestamp);
                    }
                }
            }
        });
    }else
    {
        for(auto it : this->Soamap_m[Method_ID])
        {
            if (auto observerPtr = it.lock())
                observerPtr->Notify(Service_ID_m,Method_ID,data,len,timestamp);
        }
    }
    
#ifdef DEBUG
    auto endtime = std::chrono::steady_clock::now(); //获取测试代码结束后当前系统时间
    auto duration = endtime - starttime;   //计算代码运行时间
    SPDLOG_INFO("module[{}] Service_ID[{}] Method_ID[{}] Update time[{}]",name_m,Service_ID_m,Method_ID,std::chrono::duration_cast<std::chrono::nanoseconds>(duration).count());
#endif
}

tp_info_t subject_impl::getter_threadpool_info()
{
    return thread_pool_m.getter_tp_info();
}

soam_def_type.hpp
这里是类型的定义

#ifndef __SOAM_DEF_TYPE__
#define __SOAM_DEF_TYPE__

#include <stdint.h>
#include <functional>
#include <utility>
#include <memory>
namespace SOAM
{
    //被观察者发布消息模式选择,异步or同步
    enum class subject_launch: uint8_t
    {
        ASYNC = 0,
        SYNC
    };

    //服务ID枚举
    enum class soam_server : uint16_t
    {
       TEST_TOPIC_0= 0,
       TEST_TOPIC_1= 1,
    };

    using soam_method = uint16_t;
    using soam_len = uint32_t;
    using soam_timestamp = uint64_t;  
    using soam_data = const void*;
    using soam_name = std::string;
    
    using callbackfunc = std::function<void(soam_server Service_ID,soam_method Method_ID ,soam_data data,soam_len len,soam_timestamp timestamp)>;
    using callbackkey = std::pair<soam_server,uint16_t>;
}
#endif

soam_testcase.hpp

```cpp
#ifndef __SOAM_TESTCASE__
#define __SOAM_TESTCASE__
#include "soam_def_type.hpp"
#include "subject_impl.hpp"
#include "observer_impl.hpp"
#include <mutex>
using namespace SOAM;
/*使用方法
*1:如果模块同时是观察者和被观察者,需要同时继承<subject_impl>,<observer_impl>
*2:如果仅为观察者,只需要继承<observer_impl>,如果仅为被观察者,只需要继承<subject_impl>
*3:如果是被观察者,必须枚举可被观察的Methodid,并在构造subject_impl时传入枚举的最大值,以及该模块的ServiceId(soam_def_type.hpp中获取)以助于被观察在注册回调和发布服务时进行校验
*4:如果是观察者,必须重写<observer_impl>的Notify接口,获取被观察者发布的数据并实现业务逻辑
*5:如果是观察者,Notify接口要加互斥锁,避免多线程同时发布服务时造成线程冲突。
*6:如果是被观察者,根据业务逻辑进行发布数据,调用<subject_impl>的Update接口
*/
class Instance_1 : public subject_impl,public observer_impl
{
public:

    enum : uint8_t
    {
        soam_method_e_ID_TYPE_1 = 0,
        soam_method_e_ID_TYPE_2 = 1,
        soam_method_e_ID_TYPE_MAX = 2,
    }soam_method_e_ID_e;

    ~Instance_1()
    {
        std::cout << "Instance_1::~Instance_1()" << std::endl;
    };

    static std::shared_ptr<Instance_1> get_instance()
    {
        static std::shared_ptr<Instance_1> instance(new Instance_1());
        return instance;
    }

    void Init();

    void Notify(soam_server Service_ID,soam_method Method_ID ,soam_data data,soam_len len,uint64_t timestamp) override;

private:
    Instance_1():subject_impl("ins_1",soam_server::TEST_TOPIC_0,soam_method_e_ID_TYPE_MAX,subject_launch::ASYNC),
                 observer_impl("ins_1",std::bind(&Instance_1::Notify,this,std::placeholders::_1,std::placeholders::_2,std::placeholders::_3,std::placeholders::_4,std::placeholders::_5))
    {

    };

    Instance_1& operator=(const Instance_1&) = delete;
    Instance_1(const Instance_1&) = delete;
    Instance_1(Instance_1&&) = delete;
};

class Instance_2 : public subject_impl,public observer_impl
{
public:

    enum : uint8_t
    {
        soam_method_e_ID_TYPE_1 = 0,
        soam_method_e_ID_TYPE_2 = 1,
        soam_method_e_ID_TYPE_MAX = 2,
    }soam_method_e_ID_e;

    ~Instance_2()
    {
        std::cout << "Instance_2::~Instance_2()" << std::endl;
    }

    void Init();


    static std::shared_ptr<Instance_2> get_instance()
    {
        static std::shared_ptr<Instance_2> instance(new Instance_2());
        return instance;
    }

    void Notify(soam_server Service_ID,soam_method Method_ID ,soam_data data,uint32_t len,uint64_t timestamp) override;

private:
    Instance_2():subject_impl("Ins_2",soam_server::TEST_TOPIC_1,soam_method_e_ID_TYPE_MAX,subject_launch::ASYNC),
                 observer_impl("Ins_2",std::bind(&Instance_2::Notify,this,std::placeholders::_1,std::placeholders::_2,std::placeholders::_3,std::placeholders::_4,std::placeholders::_5))
    {
 
    };

    Instance_2& operator=(const Instance_2&) = delete;
    Instance_2(const Instance_2&) = delete;
    Instance_2(Instance_2&&) = delete;
};



class Instance_3 : public subject_impl,public observer_impl
{
public:
    enum : uint8_t
    {
        soam_method_e_ID_TYPE_1 = 0,
        soam_method_e_ID_TYPE_2 = 1,
        soam_method_e_ID_TYPE_MAX = 2,
    }soam_method_e_ID_e;

    ~Instance_3()
    {
        std::cout << "Instance_3::~Instance_3()" << std::endl;
    }

    static std::shared_ptr<Instance_3> get_instance()
    {
        static std::shared_ptr<Instance_3> instance(new Instance_3());
        return instance;
    }
    void Init();
    void Notify(soam_server Service_ID,soam_method Method_ID ,soam_data data,uint32_t len,uint64_t timestamp) override;

private:
    Instance_3():subject_impl("Ins_3",soam_server::TEST_TOPIC_2,soam_method_e_ID_TYPE_MAX,subject_launch::ASYNC),
                 observer_impl("Ins_3",std::bind(&Instance_3::Notify,this,std::placeholders::_1,std::placeholders::_2,std::placeholders::_3,std::placeholders::_4,std::placeholders::_5))
    {

    };

    Instance_3& operator=(const Instance_3&) = delete;
    Instance_3(const Instance_3&) = delete;
    Instance_3(Instance_3&&) = delete;
};
#endif

soam_testcase.cpp
测试用例
模拟三个模块,既是subject,也是observer
相互注册对方的多个topic,同时异步发布自己的所有topic

#include "soam_testcase.hpp"
#include <future>
#include "spdlog/spdlog.h"
#include "spdlog/fmt/bin_to_hex.h"
void Instance_1::Init()
{
    std::shared_ptr<Instance_1> intance_1 = Instance_1::get_instance();
    std::shared_ptr<Instance_2> intance_2 = Instance_2::get_instance();
    std::shared_ptr<Instance_3> intance_3 = Instance_3::get_instance();

    intance_2->RegisterSuject(intance_2->soam_method_e_ID_TYPE_1, intance_1);
    intance_2->RegisterSuject(intance_2->soam_method_e_ID_TYPE_2, intance_1);
    intance_3->RegisterSuject(intance_3->soam_method_e_ID_TYPE_1, intance_1);
    intance_3->RegisterSuject(intance_3->soam_method_e_ID_TYPE_2, intance_1);
   
}


void Instance_1::Notify(soam_server Service_ID,soam_method Method_ID ,soam_data data,uint32_t len,uint64_t timestamp)
{
    std::vector<uint8_t> tmp((uint8_t*)data,(uint8_t*)data + len);
    spdlog::info("Instance_1 notify Service_ID[{}] Method_ID[{}] len[{}] data[{}]",(uint16_t)Service_ID,(uint16_t)Method_ID,len,spdlog::to_hex(tmp));
}


void Instance_2::Init()
{
    std::shared_ptr<Instance_1> intance_1 = Instance_1::get_instance();
    std::shared_ptr<Instance_2> intance_2 = Instance_2::get_instance();
    std::shared_ptr<Instance_3> intance_3 = Instance_3::get_instance();
    
    intance_1->RegisterSuject(intance_1->soam_method_e_ID_TYPE_1, intance_2);
    intance_1->RegisterSuject(intance_1->soam_method_e_ID_TYPE_2, intance_2);
    intance_3->RegisterSuject(intance_3->soam_method_e_ID_TYPE_1, intance_2);
    intance_3->RegisterSuject(intance_3->soam_method_e_ID_TYPE_2, intance_2);
    
}

void Instance_2::Notify(soam_server Service_ID,soam_method Method_ID ,soam_data data,uint32_t len,uint64_t timestamp)
{
    std::vector<uint8_t> tmp((uint8_t*)data,(uint8_t*)data + len);
    spdlog::info("Instance_2 notify Service_ID[{}] Method_ID[{}] len[{}] data[{}]",(uint16_t)Service_ID,(uint16_t)Method_ID,len,spdlog::to_hex(tmp));
}


void Instance_3::Init()
{
    std::shared_ptr<Instance_1> intance_1 = Instance_1::get_instance();
    std::shared_ptr<Instance_2> intance_2 = Instance_2::get_instance();
    std::shared_ptr<Instance_3> intance_3 = Instance_3::get_instance();
  

    intance_1->RegisterSuject(intance_1->soam_method_e_ID_TYPE_1, intance_3);
    intance_1->RegisterSuject(intance_1->soam_method_e_ID_TYPE_2, intance_3);
    intance_2->RegisterSuject(intance_2->soam_method_e_ID_TYPE_1, intance_3);
    intance_2->RegisterSuject(intance_2->soam_method_e_ID_TYPE_2, intance_3);
    
}

void Instance_3::Notify(soam_server Service_ID,soam_method Method_ID ,soam_data data,uint32_t len,uint64_t timestamp) 
{
    std::vector<uint8_t> tmp((uint8_t*)data,(uint8_t*)data + len);
    spdlog::info("Instance_3 notify Service_ID[{}] Method_ID[{}] len[{}] data[{}]",(uint16_t)Service_ID,(uint16_t)Method_ID,len,spdlog::to_hex(tmp));
}



int main()
{
    std::shared_ptr<Instance_1> pobserver_1 = Instance_1::get_instance();
    std::shared_ptr<Instance_2> pobserver_2 = Instance_2::get_instance();
    std::shared_ptr<Instance_3> pobserver_3 = Instance_3::get_instance();

    pobserver_1->Init();
    pobserver_2->Init();
    pobserver_3->Init();
    

#if 0
    pobserver_1->UnregisterSuject(pobserver_1->Instance_1_SOA_TYPE_1,pobserver_2);
    pobserver_1->UnregisterSuject(pobserver_1->Instance_1_SOA_TYPE_2,pobserver_2);
    pobserver_1->UnregisterSuject(pobserver_1->Instance_1_SOA_TYPE_1,pobserver_3);
    pobserver_1->UnregisterSuject(pobserver_1->Instance_1_SOA_TYPE_2,pobserver_3);

    pobserver_2->UnregisterSuject(pobserver_2->Instance_2_SOA_TYPE_1, pobserver_1);
    pobserver_2->UnregisterSuject(pobserver_2->Instance_2_SOA_TYPE_2, pobserver_1);
    pobserver_2->UnregisterSuject(pobserver_2->Instance_2_SOA_TYPE_1, pobserver_3);
    pobserver_2->UnregisterSuject(pobserver_2->Instance_2_SOA_TYPE_2, pobserver_3);

    pobserver_3->UnregisterSuject(pobserver_3->Instance_3_SOA_TYPE_1, pobserver_1);
    pobserver_3->UnregisterSuject(pobserver_3->Instance_3_SOA_TYPE_2, pobserver_1);
    pobserver_3->UnregisterSuject(pobserver_3->Instance_3_SOA_TYPE_1, pobserver_2);
    pobserver_3->UnregisterSuject(pobserver_3->Instance_3_SOA_TYPE_2, pobserver_2);
   
#endif

    uint8_t* buff = new uint8_t[5]{0x0a, 0x01, 0x02, 0x03, 0x04};
    uint32_t len = 5*sizeof(uint8_t);
    pobserver_1->Update(pobserver_1->soam_method_e_ID_TYPE_1,buff,len,0);
    pobserver_1->Update(pobserver_1->soam_method_e_ID_TYPE_2,buff,len,0);
    pobserver_2->Update(pobserver_2->soam_method_e_ID_TYPE_1,buff,len,0);
    pobserver_2->Update(pobserver_2->soam_method_e_ID_TYPE_2,buff,len,0);
    pobserver_3->Update(pobserver_3->soam_method_e_ID_TYPE_1,buff,len,0);
    pobserver_3->Update(pobserver_3->soam_method_e_ID_TYPE_2,buff,len,0);
    sleep(1);
    delete[] buff;
    return 0;
}

运行结果:每个模块都能发布topic并收到来自其他模块的topic发布的通知

[2024-04-13 12:58:53.130] [info] Instance_1 notify Service_ID[1] Method_ID[0] len[5] data[
0000: 0a 01 02 03 04]
[2024-04-13 12:58:53.130] [info] Instance_2 notify Service_ID[0] Method_ID[1] len[5] data[
0000: 0a 01 02 03 04]
[2024-04-13 12:58:53.130] [info] Instance_3 notify Service_ID[0] Method_ID[1] len[5] data[
0000: 0a 01 02 03 04]
[2024-04-13 12:58:53.130] [info] Instance_1 notify Service_ID[2] Method_ID[0] len[5] data[
0000: 0a 01 02 03 04]
[2024-04-13 12:58:53.130] [info] Instance_2 notify Service_ID[0] Method_ID[0] len[5] data[
0000: 0a 01 02 03 04]
[2024-04-13 12:58:53.130] [info] Instance_3 notify Service_ID[0] Method_ID[0] len[5] data[
0000: 0a 01 02 03 04]
[2024-04-13 12:58:53.130] [info] Instance_3 notify Service_ID[1] Method_ID[0] len[5] data[
0000: 0a 01 02 03 04]
[2024-04-13 12:58:53.130] [info] Instance_2 notify Service_ID[2] Method_ID[0] len[5] data[
0000: 0a 01 02 03 04]
[2024-04-13 12:58:53.130] [info] Instance_1 notify Service_ID[1] Method_ID[1] len[5] data[
0000: 0a 01 02 03 04]
[2024-04-13 12:58:53.130] [info] Instance_3 notify Service_ID[1] Method_ID[1] len[5] data[
0000: 0a 01 02 03 04]
[2024-04-13 12:58:53.130] [info] Instance_1 notify Service_ID[2] Method_ID[1] len[5] data[
0000: 0a 01 02 03 04]
[2024-04-13 12:58:53.130] [info] Instance_2 notify Service_ID[2] Method_ID[1] len[5] data[
0000: 0a 01 02 03 04]

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值