设计模式之观察者模式

定义

观察者模式是一种行为型设计模式,它定义了对象之间的一种一对多的依赖关系,以便当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动更新。

解决问题

稳定点:“一” 对 “多”的依赖关系,“一” 变化 “多” 跟着变
变化点:“多” 增加或者减少
C++ 观察者模式可以用于解决对象之间的依赖关系问题。该模式允许多个对象同时观察一个主题对象,并在主题对象状态发生改变时自动接收通知。
通过使用观察者模式,我们可以实现松耦合的设计,从而使得主题对象和观察者对象之间的关系更加清晰和易于维护。当主题对象发生改变时,观察者对象可以自动更新自己的状态,而不需要主题对象直接通知观察者对象。

代码结构

在 C++ 中实现观察者模式,可以定义一个抽象类 Subject,它包含了添加观察者、删除观察者和通知观察者等方法接口。
然后定义一个具体的 Subject 类,继承自抽象类 Subject,实现其中的添加观察者、删除观察者与 Notify 方法。
接着定义一个抽象的 Observer 类,它包含了一个 Update 方法,用于在收到通知后进行更新操作。
最后,定义一个具体的 Observer 类,继承自抽象类 Observer,实现其中的 Update 方法,用于在收到通知后进行具体的更新操作。

设计原则

单一职责原则(SRP):观察者模式中的主题对象和观察者对象各自承担不同的职责。主题对象负责维护状态并通知观察者,而观察者对象负责处理通知并更新自身状态。这样可以使对象的职责更加清晰,更容易理解和维护。

开闭原则(OCP):通过使用观察者模式,我们可以将主题对象和观察者对象解耦,从而使得我们可以在不修改现有代码的情况下增加新的观察者对象或修改主题对象的实现。这符合开闭原则的要求,使得我们的代码更加灵活和可扩展。

依赖倒置原则(DIP):观察者模式中的主题对象和观察者对象之间是松耦合的,它们之间的依赖关系是通过抽象接口实现的。这使得我们可以更容易地替换不同的观察者对象,同时也可以更容易地修改主题对象的实现。

迪米特法则(LoD):观察者模式中的主题对象只与抽象观察者对象通信,而不需要知道具体观察者对象的实现。这符合迪米特法则的要求,使得对象之间的耦合更加松散,降低了系统的复杂度。

如何扩展

继承实现接口
调用 attach、detach

案例

气象站发布气象资料给数据中心,数据中心经过处理,将气象信息更新到两个不同的显示终端(A 和B。。。);
//一般方法
class DisplayA {
public:
    void Show(float temperature);
};

class DisplayB {
public:
    void Show(float temperature);
};

class DisplayC {
public:
    void Show(float temperature);
}

class WeatherData {};

class DataCenter {
public:
	DataCenter (): data_(0){}
	//如果通知对象增加和删除,需要在此接口中不断的修改,违反开闭原则
    void TempNotify() 
    {
        DisplayA *da = new DisplayA;
        DisplayB *db = new DisplayB;
        DisplayC *dc = new DisplayC;
        // DisplayD *dd = new DisplayD;
        float temper = this->CalcTemperature();
        da->Show(temper);
        db->Show(temper);
        dc->Show(temper);
        dc->Show(temper);
    }
    void SetDate(float data)
    {
    	data_ = data;
    	TempNotify();
    }
private:
    float data_;
};
 float CalcTemperature() 
 {
     WeatherData * data = new WeatherData ();
     // ...
     float temper/* = */;
     delete data ;
     data  = nullptr;
     return temper;
 }
int main() {
    DataCenter *center = new DataCenter;
    center->SetDate(CalcTemperature());
    return 0;
}
如果想要新增终端,需要在DataCenter 中新建终端对象,
基于观察者模式,改进后:
#include <list>
#include <algorithm>
using namespace std;
//
class IDisplay {
public:
    virtual void Show(float temperature) = 0;
    virtual ~IDisplay() {}
};

class DisplayA : public IDisplay {
public:
    virtual void Show(float temperature) {
        cout << "DisplayA Show" << endl;
    }
private:
    void jianyi();
};

class DisplayB : public IDisplay{
public:
    virtual void Show(float temperature) {
        cout << "DisplayB Show" << endl;
    }
};

class DisplayC : public IDisplay{
public:
    virtual void Show(float temperature) {
        cout << "DisplayC Show" << endl;
    }
};

class DisplayD : public IDisplay{
public:
    virtual void Show(float temperature) {
        cout << "DisplayC Show" << endl;
    }
};

class WeatherData {};
class Center{
public:
    virtual void Attach(IDisplay* observer) = 0;
    virtual void Detach(IDisplay* observer) = 0;
    virtual void Notify() = 0;
};

// 应对稳定点,抽象
// 应对变化点,扩展(继承和组合)
class DataCenter : public Center
{
public:
    void Attach(IDisplay * ob) override {// }
    void Detach(IDisplay * ob) override { // }
    void Notify() override 
    {
        for (auto iter : obs) {
            iter.Show(data_);
        }
    }
	void SetDate(float data)
	{
		data_ = data;
		Notify();
	}
private:// 接口隔离
    float data_
    std::list<IDisplay*> obs;
};

 float CalcTemperature() 
 {
     WeatherData * data = new WeatherData ();
     // ...
     float temper/* = */;
     delete data ;
     data  = nullptr;
     return temper;
 }
int main() {
    // 单例模式
    DataCenter *center = new DataCenter;
    // ... 某个模块
    IDisplay *da = new DisplayA();
    center->Attach(da);

    // ...
    IDisplay *db = new DisplayB();
    center->Attach(db);
    
    IDisplay *dc = new DisplayC();
    center->Attach(dc);

    center->SetDate(CalcTemperature());
    
    //-----
    center->Detach(db);
    center->SetDate(CalcTemperature());

    //....
    center->Attach(dd);

    center->SetDate(CalcTemperature());
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值