您的位置:首页 > 其它

[置顶] 观察者模式及如何通过消息机制(观察者模式)实现模块间解耦

2018-03-06 11:27 459 查看

1、讲一下什么是观察者模式

什么是观察者模式呢,观察者模式又叫做订阅发布模式,类似这样的例子生活里随处可见,比如公众号,比如微博关注的功能,这都是订阅发布模式,我们对一个公众号感兴趣,就会去关注一个公众号,这个公众号有了什么新的文章,新的内容,就会推送给所有关注了这个公众号的微信号,如果某一天我们对这个公众号不再感兴趣,我们就可以取消对它的关注,后面这个公众号再有什么新的内容,也不会再推送给我们,不会再提醒我们。

下面通过代码的形式,实现一个简单的订阅发布模式

第一版



class Subject
{
public:
void registerObserver (CatObserver * a);
void removeObserver (CatObserver * a);
notifyAll();
private:
std::vector< CatObserver *> accounts;
};

class CatObserver
{
void update();
}


这个版本的问题很明显就是没有扩展性,就像我上次讲开闭原则

说的,Subject模块依赖了具体的CatObserver类,后面如果想扩展,让一个DogObserver也可以订阅Subject的主题,那这样的设计就没办法实现了。

第二版



class Subject
{
public:
void registerObserver (Observer * a);
void removeObserver (CatObserver * a);
notifyAll();
private:
std::vector< Observer *> accounts;
};

class Observer
{
virtual void update() = 0;
}
class CatObserver : public Observer
{
virtual void update() override
{
//cat observer update
};
}
class DogObserver : public Observer
{
virtual void update() override
{
//dog observer update
};
}
class DuckObserver : public Observer
{
virtual void update() override
{
//duck observer update
};
}




第二版我们让Subject不再依赖一个具体的类,而是依赖一个接口,主题不再需要知道观察者具体类是谁,做了些什么和其他的任何细节,任何时候我们都可以增加新的观察者,因为Sbuject唯一依赖的东西就是一个实现Observer接口的对象列表,所以我们可以随时增加观察者。事实上,再运行时我们可以用新的观察者取代现有的观察者,主题也会收到任何影响。同样的,也可以再任何时候删除某些观察者。

改变主题或者观察者任何其中一方,都不会影响另一方。因为两者是送耦合的,所以只要他们的接口仍被遵循,我们就可以自由的改变他们。送耦合的设计之所以能让我们建立有弹性的OO系统,能够应对变化,是因为对象之间的相互依赖降到了最低,这就是松耦合的威力。

2、如何通过观察者模式实现模块的解耦

我们都知道,消息机制一直是软件开发中减少模块之间耦合的标准方式,那消息机制其实就是通过观察者模式实现的,下面我们举一个简单的例子,看看是如何通过消息,减少类 A 和类 B之间的耦合度的。

下面是传统的方法,实现 A 对 B 类的某个方法的调用,不使用消息机制的传统方法,A 需要持有 B 的对象,并且 A 要知道所要调用的B的方法,这样 A 和 B 就强耦合在了一起,一旦 B 类发生变化,A 类就可能要重新编译,而且如果 doSomethingBSpecial 这个方法需要改名,或者修改参数,A 类就也需要修改,这样的依赖关系就带来了诸多的不便。

#include "stdafx.h"
#include <vector>
#include <iostream>
//不使用消息机制的传统方法,A 需要持有 B 的对象,并且 A 要知道所要调用的B的方法
//这样A 和 B就强耦合在了一起,一旦 B 类发生变化,A 类就可能要重新编译,而且如果
//doSomethingBSpecial这个方法需要改名,或者修改参数,A 类就也需要修改,这样的
//依赖关系就带来了诸多的不便。
class B
{
public:
void doSomethingBSpecial()
{
//B 做一些事情
std::cout << "B do something..." << std::endl;
}
};

class A
{
public:
A(B* b) :m_b(b){}

void doSomethingASpecial()
{
//在这个方法中,会调用B 的 doSomethingBSpecial
m_b->doSomethingBSpecial();
}

private:
B* m_b;
};

int _tmain(int argc, _TCHAR* argv[])
{
A a(new B());
a.doSomethingASpecial();
return 0;
}


下面使用消息机制实现同样的调用,这样 A 就不需要引用 B 的对象,同时 A 也不需要知道 B 的方法,实现了 A 类 和 B 类的解耦。

下面简易的实现了一个的消息处理器,只具备简易的注册,删除和触发事件的功能,在客户的代码中,把 B 的对象注册到消息处理器,使 B 可以处理 doSomethingASpecial 这个消息,然后在 A 类需要调用 B 的方法的地方, 可以直接用消息处理器处理 doSomethingASpecial 这个消息,MsgMgr::handle(“doSomethingASpecial”) 这样调用以后,所有注册过 doSomethingASpecial 这个消息的对象(包括 B 对象),都会接受并且处理这个消息,B 对象的 handle 方法就会被调用,然后在这个方法里就可以去调用 B 的 doSomethingBSpecial 方法,这样就实现了 A 对 B类的 doSomethingBSpecial 方法的调用, 去掉了 A 和 B 之间的耦合依赖关系。

#include "stdafx.h"
#include <vector>
#include <iostream>
#include <map>
#include <string>
//使用消息机制,A 就不需要持有 B 的对象,
//消息接受者接口
class MsgReceiver
{
public:
virtual void handle() = 0;
};
//这里实现一个简易的消息处理器,只具备简易的,注册,删除,和触发事件的功能
static std::map<std::string, MsgReceiver*> m_allMsgRecevers;
class MsgMgr
{
public:
static void addReceiver(std::string msg, MsgReceiver* receiver)
{
m_allMsgRecevers.emplace(msg, receiver);
}
static void removeReceiver(std::string msg)
{
m_allMsgRecevers.erase(msg);
}
static void handle(std::string msg)
{
m_allMsgRecevers.at(msg)->handle();
}
};
class A
{
public:
void doSomethingASpecial()
{
//这里如果想调用 B 的 doSomethingBSpecial 方法
//可以直接用消息处理器处理 doSomethingASpecial 这个消息
//因为 B 已经注册声明过可以处理 doSomethingASpecial 这个消息
//MsgMgr::handle("doSomethingASpecial") 这样调用以后,所有
//注册过 doSomethingASpecial 这个消息的对象,都会接受并且处理这个消息
//这样就去掉了A 和 B之间的耦合依赖关系
MsgMgr::handle("doSomethingASpecial");
}
};
class B : public MsgReceiver
{
public:
void doSomethingBSpecial()
{
//B 做一些事情
std::cout << "B do something..." << std::endl;
}

virtual void handle() override
{
doSomethingBSpecial();
}
};
int _tmain(int argc, _TCHAR* argv[])
{
A a;
B* b = new B;
//这里把 B 的对象注册到消息处理器,使 B 可以处理 doSomethingASpecial 这个消息
MsgMgr::addReceiver("doSomethingASpecial", b);
a.doSomethingASpecial();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐