观察者模式(c++)(组建协作型模式)

mac2022-06-30  26

观察者(Observer)模式

应用场景使用观察者模式的目的类图适用场景

应用场景

某一天,你的老板希望你在某个项目的文件下载的界面,加一个进度条,方便用户知道现在文件下载到那一步了。于是乎,你写了个文件加载类(FileLoader),一个进度条类(ShowRate)。把文件加载的进度实时地显示给用户。就像这样

class ShowRateA{ public: void setRate(float rate){ mRate = rate; } void showRate(){ //showRate } private: float mRate; } class FileLoaderA{ public: FileLoader(ShowRate* showRate) :mShowRate(showRate){} void loadFile(const char *fliePath){ //假设有总共10个文件 for(int i = 0;i<10;i++){ //加载文件 mShowRate->setRate(i/10.0); mShowRate->showRate(); } } private: ShowRate* mShowRate; } int main(void){ ShowRateA* showRate = new ShowRateA(); FileLoaderA *fileLoader = new FileLoaderA(showRate); fileLoader->loadFile("一个神奇的文件路径"); delete fileLoader delete showRate; return 0; }

看起来好像是解决了问题。实际上这时候你确实解决了问题。

but过了几天,你的老板发现,之前的进度展示界面好像做的太难看了,于是找人写了个更好看的界面,于是需要一个新的进度条(ShowRateB),你需要的是把之前的进度条换掉,这时候你只能重新编译main函数,并且重新编译一大堆文件,导致软件出现一大堆莫名其妙的bug,于是你加班到12点,第二天疯狂掉头发,有过了两天,老板发现之前的文件加载类不够高效,于是找人写了个新的文件加载类(FileLoaderB),于是又要重写main函数,然后一大堆bug又来了,又加班,掉发。 最后秃头。 为什么你会秃头呢?因为这样写代码严重违反了依赖倒置原则,极有可能造成莫名其妙的代码错误。(之前有一篇博客专门讲了软件设计6大原则)

使用观察者模式的目的

定义了一种一对多的依赖关系,让多个观察者对象同时监听某一主题对象,在主题对象的状态发生变化时,会通知所有的观察者。 隔离变化 在实际的项目中,使用配置文件+合理的设计模式,可以做到只更新需要的一部分,

class Observer{ public: virtual void update(float rate) = 0; virtual void showRate() = 0; virtual ~Observer(); }; class ShowRateA : public Observer{ public: virtual void update(float rate){ mRate = rate; } virtual void showRate(){ //showRate } private: float mRate; }; class Subject{ public: virtual void loadFile(const char *fliePath) = 0; virtual ~Subject(); }; class FileLoaderA : public Subject{ public: FileLoaderA (Observer *observer) :mObserver(observer){} virtual void loadFile(const char *fliePath){ //假设有总共10个文件 for(int i = 0;i<10;i++){ //加载文件 mObserver->update(i/10.0); mObserver->showRate(); } } private: Observer *mObserver; }; int main(void){ Observer *showRate = new ShowRateA(); Subject *fileLoader = new FileLoaderA(showRate); fileLoader->loadFile("一个神奇的文件路径"); delete fileLoader; delete showRate; return 0; }

这样写的话就算你再写了个新的ShowRateB或者新的FileLoaderB,也能很好的支持,不需要改写各自代码,可以有人会想,这样写也不main函数,实际上一般情况下,决定加载哪一个类的不是main函数里面的那几行代码,实际上很多软件系统都有xml文件,软件通过加载xml文件来决定加载哪一个类。当你需要更新一个类时,只需要编译新的那个类,然后改写xml文件就行了。(这个操作设计到后面要讲的工厂模式,这里可以先听着,后面会讲)

类图

Subject(目标) ——目标知道它的观察者。可以有任意多个观察者观察同一个目标; ——提供注册和删除观察者对象的接口。

Observer(观察者) ——为那些在目标发生改变时需获得通知的对象定义一个更新接口。

ConcreteSubject(具体目标) ——将有关状态存入各ConcreteObserver对象; ——当它的状态发生改变时,向它的各个观察者发出通知。

ConcreteObserver(具体观察者) ——维护一个指向ConcreteSubject对象的引用; ——存储有关状态,这些状态应与目标的状态保持一致; ——实现Observer的更新接口以使自身状态与目标的状态保持一致。

适用场景

在以下任一情况下都可以使用观察者模式:

当一个抽象模型有两个方面,其中一个方面依赖于另一方面。将这二者封装在独立的对象中以使它们可以各自独立的改变和复用;当对一个对象的改变需要同时改变其它对象,而不知道具体有多少对象有待改变;当一个对象必须通知其它对象,而它又不能假定其它对象是谁;也就是说,你不希望这些对象是紧密耦合的。
最新回复(0)