简介
- 定义了一种一对多的依赖关系, 即当一个对象subject改变时, 会通知所有与之关联的对象observer并自动更新;
- 也叫发布-订阅publish-subscribe, 依赖Dependents;
- 这些依赖的对象之间可能不知道对方的存在;
- 当subject发生变化, observer会查询目标并更新状态;
适用
- 当一个对象发生变化时希望通知另几个对象,但同时又不希望这些对象是紧密耦合;
结构
- subject类要登记所有的observer,以通知它们, 而具体的observer则要保留想观察的subject的引用,以用来查阅subject的变化并更新;
- observer观察多个subject是可能的, 此时就要扩展update()接口, 让observer知道是哪个suject发来的更新通知;
- 也可以扩展observer的注册接口, 让observer注册为仅对特定的通知感兴趣, 这样不至于每次接受到通知就出更新状态, 而这个状态可能对该observer来说没有任何更新意义;
- 当一个observer关注多个subject时, 如果采用简单的通知方式即subject每次更新就通知observer, 则很有可能会发生通知冗余的情况, 这时可以通过一个中间的对象:ChangeManager来管理subject的更新, 只有当subject全部跟新完后, 才会向observer发送更新通知, 这样就保证了observer只更新一次;
例子
小明和小梦正式走到一起后, 小明才发现原来相爱容易相处难, 为了将小梦留着身边,小明也是尽心尽力, 得对小梦的各种变化做出相应的应对; 比如哪天小梦不高兴了, 小明就不得不硬着头皮对小梦的各种情绪给予笑脸相迎, 而小梦心情好了那小明的春天就来了, 就可以向刚开始谈恋爱时一样各种调戏小梦了; 哪天小梦想吃零食了,小明立马会上淘宝购各种好吃的….
上面的例子就可以看成是小明订阅了小梦的需求, 并在小梦需求发生变化时立马做出相应的改变, 只有这样才能抱得美人归…
实现
class Observer;
// 抽象主题,这里表示情绪, 在主题类里添加了当前情绪的名字
class Mood
{
public:
Mood():mood(""){}
void Attach(Observer* obsvr) { mObsvr.insert(obsvr);}
void Dettach(Observer* obsvr) {mObsvr.erase(obsvr);}
virtual void Notify(string str) {};
string GetMood() { return mood;}
protected:
set<Observer*> mObsvr;
void ChangeMood(string str)
{
mood = str;
cout<<"xiaomeng become "<<mood<<endl;
}
string mood;
};
// 抽象观察者
class Observer
{
public:
virtual void Updata() = 0;
virtual void RegisteSubject(Mood* mood) = 0;
};
// 女朋友的情绪
class GirlFriendMood : public Mood
{
public:
GirlFriendMood(string str)
{
mood = str;
cout<<"xiaomeng feels "<<str<<" today!"<<endl;
}
void Notify(string str)
{
ChangeMood(str);
for(set<Observer*>::iterator itr = mObsvr.begin(); itr != mObsvr.end();++itr)
(*itr)->Updata();
}
};
// 男朋友时刻注意着女朋友的情绪变化
class BoyFriend:public Observer
{
public:
BoyFriend(string name):mGirlMood(0),Boy(name){};
virtual void Updata()
{
cout<<Boy<<"'s emotion become unstable,"<<Boy<<" need cooperate with xiaomeng!"<<endl;
string str = mGirlMood->GetMood();
cout<<Boy<<" know xiaomeng is "<<str<<endl;
}
virtual void RegisteSubject(Mood* mood)
{
mGirlMood = mood;
}
private:
Mood* mGirlMood;
string Boy;
};
int main()
{
Observer* xiaoming = new BoyFriend("xiaoming");
Mood* xiaomeng = new GirlFriendMood("happy");
xiaoming->RegisteSubject(xiaomeng);
xiaomeng->Attach(xiaoming);
xiaomeng->Notify("feels hot");
return 0;
}
总结
- 显然,这里的观察者可以是多个并添加到相应的subject的通知集合中即可;
- 同时观察者也可以同事注意多个subject;
- 该模式用于当一个对象改变需要同时改变其它对象的时候;
- 且主题可以不知道有多少个对象需要通知; 该方法就是将subject与观察者双方解除耦合, 让双方都依赖与抽象而不是具体; 使得两端的变化都不会改动另一方;