设计模式学习(行为型模式)--观察者模式
定义
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并更新。
适用情况
当一个对象的改变需要改变其他对象的时候,且它不知道具体有多少对象有待改变。
使用情况举例
场景来自《大话设计模式》。
办公室同事沉迷于炒股,上班时间也在看股票,老板在办公室时会被批评,于是拜托秘书在老板回来时通知一下,关闭炒股页面,继续工作,避免被老板发现。同样的,还有看NBA和打游戏的同事。基于此场景,构建UML类图,并编写相关代码。
UML类图
这里用C++实现,因此只有抽象类,没有接口。
实现代码
抽象目标类
class Subject
{
public:
Subject();
virtual void registerListenner(Observer *observer) = 0;
virtual void removeListenner(Observer *observer) = 0;
virtual void notify() = 0;
};
秘书类(具体目标类)
#include "secretary.h"
Secretary::Secretary()
{
fellowList.clear();
this->action = false;
}
//添加需要通知的同事
void Secretary::registerListenner(Observer *observer)
{
fellowList.push_back(observer);
}
//去除不再需要通知的同事
void Secretary::removeListenner(Observer *observer)
{
for (vector<Observer*>::iterator iter=fellowList.begin(); iter!=fellowList.end(); iter++)
{
if( *iter == observer)
{
fellowList.erase(iter);
break;
}
}
}
//通知同事
void Secretary::notify()
{
for (vector<Observer*>::iterator iter=fellowList.begin(); iter!=fellowList.end(); iter++)
{
if(action)
{
(*iter)->onBossComing(SECRETARY_MESSAGE_COME);
}
else
{
(*iter)->onBossOut(SECRETARY_MESSAGE_OUT);
}
}
}
//设置当前老板位置,true表示回来了,false表示走了
void Secretary::setAction(bool bossAction)
{
this->action = bossAction;
notify();
}
另一个具体目标类代码类似
玩游戏的同事类(具体观察者类)
#include "gameobserver.h"
gameObserver::gameObserver()
{
}
gameObserver::gameObserver(string name)
{
this->name = name;
}
//老板来了
void gameObserver::onBossComing(string bossMessage)
{
cout<<bossMessage<<"-->";
stopGame();
}
//老板走了
void gameObserver::onBossOut(string bossMessage)
{
cout<<bossMessage<<"-->";
doGame();
}
void gameObserver::stopGame()
{
cout<<name<<"停止玩游戏,开始工作"<<endl;
}
void gameObserver::doGame()
{
cout<<name<<"继续玩游戏"<<endl;
}
另外两个具体观察者类代码类似
主函数
Boss boss;
Secretary secretary;
gameObserver gameFellow("张三");
stockObserver stockFellow("李四");
NBAObserver nbaFellow("王五");
//监听老板
boss.registerListenner(&gameFellow);
boss.registerListenner(&stockFellow);
boss.registerListenner(&nbaFellow);
//监听秘书
secretary.registerListenner(&gameFellow);
secretary.registerListenner(&stockFellow);
secretary.registerListenner(&nbaFellow);
//老板回来了
boss.setAction(true);
cout<<endl;
//老板走了
boss.setAction(false);
cout<<endl;
//秘书发现老板回来了
secretary.setAction(true);
cout<<endl;
//秘书发现老板走了
secretary.setAction(false);
cout<<endl;
//老板允许上班看股票,移除看股票同事对老板的监听
cout<<"上班时间允许看股票了"<<endl;
cout<<endl;
boss.removeListenner(&stockFellow);
boss.setAction(true);
cout<<endl;
boss.setAction(false);
cout<<endl;
//上班允许看比赛,移除看比赛同事对秘书的监听
cout<<"上班时间可以看比赛了"<<endl;
cout<<endl;
secretary.removeListenner(&nbaFellow);
secretary.setAction(true);
cout<<endl;
secretary.setAction(false);
cout<<endl;
运行效果
我回来了-->张三停止玩游戏,开始工作
我回来了-->李四停止看股票,开始工作
我回来了-->王五停止看NBA比赛,开始工作
我走了-->张三继续玩游戏
我走了-->李四继续看股票
我走了-->王五继续看NBA比赛
老板回来了-->张三停止玩游戏,开始工作
老板回来了-->李四停止看股票,开始工作
老板回来了-->王五停止看NBA比赛,开始工作
老板走了-->张三继续玩游戏
老板走了-->李四继续看股票
老板走了-->王五继续看NBA比赛
上班时间允许看股票了
我回来了-->张三停止玩游戏,开始工作
我回来了-->王五停止看NBA比赛,开始工作
我走了-->张三继续玩游戏
我走了-->王五继续看NBA比赛
上班时间可以看比赛了
老板回来了-->张三停止玩游戏,开始工作
老板回来了-->李四停止看股票,开始工作
老板走了-->张三继续玩游戏
老板走了-->李四继续看股票
总结
观察者模式优点
- 降低了目标与观察者之间的耦合关系,两者之间是抽象耦合关系。符合依赖倒置原则。
- 目标与观察者之间建立了一套触发机制。
观察者模式缺点
- 目标与观察者之间的依赖关系并没有完全解除,而且有可能出现循环引用
- 当观察者对象很多时,通知的发布会花费很多时间,影响程序的效率
参考资料
- http://c.biancheng.net/view/1390.html
- 《大话设计模式》P123-P140