一 应用场景
社交网络中,当我们关注的一个人发表状态后粉丝就会有通知。这就用到了观察者模式,即:当一个对象发生改变的时候,其他对象将相应的做出反应。
二 定义
观察者模式 Observer Pattern: 定义对象之间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新。观察者模式的别名包括发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。观察者模式是一种对象行为型模式。
Subject 目标:被观察的对象。在目标中定义了一个观察者集合,一个观察目标可以接受任意数量的观察者来观察。提供注册和删除观察者对象的接口。同时定义notify的方法。可以是抽象类或者具体类。
ConcreteSubject具体目标:具体目标是目标类的子类,通常它包含有经常发生改变的数据,当它的状态发生改变时,向它的各个观察者发出通知。
Observer 观察者:观察者将对观察目标的改变做出反应,观察者一般定义为接口,该接口声明了更新数据的方法update(),因此又称为抽象观察者。
ConcreteObserver具体观察者:在具体观察者中维护一个指向具体目标对象的引用,它存储具体观察者的有关状态,这些状态需要和具体目标的状态保持一致;它实现了在抽象观察者Observer中定义的update()方法。
观察者模式描述了如何建立对象与对象之间的依赖关系,以及如何构造满足这种需求的系统。观察者模式包含观察目标和观察者两类对象,一个目标可以有任意数目的与之相依赖的观察者,一旦观察目标的状态发生改变,所有的观察者都将得到通知。
三 C++实现
Blog.h
#pragma once
#include <list>
#include <iterator>
#include "Observer.h"
using namespace std;
class Blog
{
public:
Blog(){}
virtual ~Blog(){}
void Attach(Observer * _observer) {
obs_list.push_back(_observer);
}
void Remove(Observer * _observer){
obs_list.remove(_observer);
}
void Notify(){
list<Observer *>::iterator iter = obs_list.begin();
for(;iter!=obs_list.end();iter++){
(*iter)->Update();
}
}
virtual void setStatus(std::string _status){
m_status = _status;
}
virtual std::string getStatus(){
return m_status;
}
private:
std::list<Observer *> obs_list;
protected:
std::string m_status;
};
Csdnblog.h
#pragma once
#include <string>
#include "Blog.h"
using namespace std;
class CsdnBlog:public Blog
{
public:
CsdnBlog(std::string _blog_name):blog_name(_blog_name){}
virtual ~CsdnBlog(){}
void setStatus(std::string _str){
m_status = "csdn notify:" + blog_name + _str;
}
std::string getStatus(){
return m_status;
}
private:
std::string blog_name;
};
Observer.h
#pragma once
class Observer
{
public:
Observer() {}
virtual ~Observer() {}
virtual void Update() {}
};
BlogObserver.h
#pragma once
#include <string>
#include <iostream>
#include "Observer.h"
#include "Blog.h"
using namespace std;
class BlogObserver : public Observer
{
public:
BlogObserver(std::string _name, Blog * _blog):m_name(_name), m_blog(_blog){}
void Update(){
std::string status = m_blog->getStatus();
std::cout << m_name << " --- " << status<< std::endl;
}
private:
std::string m_name;
Blog * m_blog;
};
main.cpp
#include <iostream>
#include "Blog.h"
#include "CsdnBlog.h"
#include "BlogObserver.h"
using namespace std;
int main()
{
Blog * blog = new CsdnBlog("C++");
Observer * observer1 = new BlogObserver("ob1", blog);
blog->Attach(observer1);
blog->setStatus("publish a blog");
blog->Notify();
delete(blog);
blog = NULL;
delete(observer1);
observer1 = NULL;
system("pause");
return 0;
}
四 总结
优点:
1 观察者模式可以实现表示层和数据逻辑层的分离,定义了稳定的消息更新传递机制,并抽象了更新接口,使得可以有各种各样不同的表示层充当具体观察者角色。
2 观察者模式在观察目标和观察者之间建立一个抽象的耦合。观察目标只需要维持一个抽象观察者的集合,无须了解其具体观察者。由于观察目标和观察者没有紧密地耦合在一起,因此它们可以属于不同的抽象化层次。
3 观察者模式支持广播通信,观察目标会向所有已注册的观察者对象发送通知,简化了一对多系统设计的难度。
4 观察者模式满足“开闭原则”的要求,增加新的具体观察者无须修改原有系统代码,在具体观察者与观察目标之间不存在关联关系的情况下,增加新的观察目标也很方便。
缺点
1 如果一个观察目标对象有很多直接和间接观察者,将所有的观察者都通知到会花费很多时间。
2 如果在观察者和观察目标之间存在循环依赖,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。