观察者模式(observer)用于输出算法的中间过程

前言

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

其中subject类必须的成员:
1,vector<Observer*> m_observers;
2,add_observer(Observer* observer);
3,remove_observer(Observer* observer);
4,notify();

Observer类必须的成员:
1,get_notify();

本例背景阐述

一个算法常常需要包含多个步骤,而在调试算法的时候,算法工程师需要对每一个步骤进行输出,确保每一个步骤的结果都符合预期。本例以医学图像分割为例对观察者模式进行分析,其中算法的实现过程为Subject,输出中间过程的类为Observer。

本例定义的图像分割包含4个步骤:
1,原始图像重采样到算法需要的分辨率;
2,对图像进行归一化;
3,采用大津阈值对图像进分割;
4,将分割结果重采样回原始分辨率。

代码实现过程

头文件代码段和定义Observer 和Subject 两个类。

#include <iostream>
#include <vector>

using namespace std;

class Observer;
class Subject;

观察者模块,先定义了抽象接口类和纯虚函数,然后通过继承实现Debug类并重写纯虚函数。

#pragma region 观察者模块
class Observer
{
    public:
    virtual void update(const char* msg) =0;
    virtual ~Observer(){};
};

class Debug : public Observer
{
public:
    void update(const char* msg);
    virtual ~Debug(){};
};

void Debug::update(const char* msg)
{
    cout<<"Debug result:"<<msg<<endl;
}

#pragma endregion

被观察者模块,先定义算法的抽象接口类,然后通过继承实现Segment类。

#pragma region 被观察者模块
class Subject
{
    public:
    virtual void add_observer(Observer* observer) = 0;
    virtual void remove_observer(Observer* observer) = 0;
    virtual void notify(const char* msg) = 0;
    virtual ~Subject(){};

};

class Segment: public Subject
{
    public:
    
    void add_observer(Observer* observer);
    void remove_observer(Observer* observer);
    void notify(const char* msg);

    void run_alg();

    private:
    void resample_image(){
        cout<<"重采样完成."<<endl;
    }

    void normalization(){
        cout<<"归一化完成."<<endl;
    }

    void otsu_threshold(){
        cout<<"大津阈值处理完成."<<endl;
    }

    void resample_ref(){
        cout<<"重采样回原始分辨率完成."<<endl;
    }

    vector<Observer*> m_observers;

};

void Segment::add_observer(Observer* observer)
{
    auto it = find(m_observers.cbegin(), m_observers.cend(), observer);
    if (it != m_observers.cend()){
        cout<<"add_observer faild, becouse the observer exist."<<endl;
    }
    else{
        m_observers.push_back(observer);
    }
    
}

void Segment::remove_observer(Observer* observer)
{
    auto it = find(m_observers.cbegin(), m_observers.cend(), observer);
    if(it != m_observers.cend()){
        m_observers.erase(it);
    }
    else{
        cout <<"observer not in list, cannot remove it."<<endl;
    }
}

void Segment::notify(const char* msg)
{
    for(const auto t_elem : m_observers){
        t_elem->update(msg);
    }
}

void Segment::run_alg()
{
    resample_image();
    notify("重采样结果正确");

    normalization();
    notify("归一化结果正确");

    otsu_threshold();
    notify("大津阈值结果正确");

    resample_ref();
    notify("重采样回原始分辨率正确");

}

#pragma endregion

测试main函数代码

int main(int argc, char const *argv[])
{
    unique_ptr<Segment> segment_ptr(new Segment());
    unique_ptr<Debug> debug_ptr_01(new Debug());
    unique_ptr<Debug> debug_ptr_02(new Debug());
    unique_ptr<Debug> debug_ptr_03(new Debug());

    // 实际应用中,只需要修改这里的代码就能控制是否输出中间过程
    segment_ptr->add_observer(debug_ptr_01.get());
    segment_ptr->add_observer(debug_ptr_02.get());
    segment_ptr->add_observer(debug_ptr_01.get()); // 测试重复添加观察者
    segment_ptr->remove_observer(debug_ptr_03.get()); // 测试不存在的观察者是否可以移除

    segment_ptr->run_alg();

    cout<< "\n\n移除观察者后的运行效果测试." << endl;
    segment_ptr->remove_observer(debug_ptr_01.get());
    segment_ptr->remove_observer(debug_ptr_02.get());
    
    segment_ptr->run_alg();

    
	
	return 0;
}

输出结果如下:

$ ./observer.exe
add_observer faild, becouse the observer exist.
observer not in list, cannot remove it.
重采样完成.
Debug result:重采样结果正确
Debug result:重采样结果正确
归一化完成.
Debug result:归一化结果正确
Debug result:归一化结果正确
大津阈值处理完成.
Debug result:大津阈值结果正确
Debug result:大津阈值结果正确
重采样回原始分辨率完成.
Debug result:重采样回原始分辨率正确    
Debug result:重采样回原始分辨率正确    


移除观察者后的运行效果测试.
重采样完成.
归一化完成.
大津阈值处理完成.
重采样回原始分辨率完成.
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值