什么是观察者模式?
观察者模式, 定义了一种对象间的 一对多的依赖关系, 让多个观察者同时监听某一个主题对象。 当主题对象的状态发生改变时, 同通知他所有的观察者, 让他们能够自动更新。
背景
很多时候, 在应用程序的一部分发生改变时, 需要同时更新应用程序的其他部分。 一种办法是, 让观察者定期反复检查主题对象的状态来进行更新, 但这种办法存在两个主要的问题:
- 占用大量的cpu时间来检测新的状态, 造成资源浪费
- 依赖于检测更新的时间间隔, 更新没有及时性
观察者模式可以解决这些问题。
如何实现
观察者模式中有如下角色:
- 抽象主题(Subject ): 被观察的对象, 抽象主题把他所有的观察者都保存在一个集合里(list), 每个主题可以有任意数量的观察者。 抽象主题需要提供添加和删除观察者的接口。抽象主题需要声明通知方法, 如notify(), 用于在自身状态发生改变时通知所有的观察者。
- 具体主题(ConcreteSubject ):抽象主题的子类,
- 抽象观察者(Observer): 声明了更新数据的方法, 如update(), 对主题对象的变化做出更新反应。
- 具体观察者(ConcreteObserver): 抽象观察者的子类, 实现了更新方法。 具体观察者中维护了一个具体主题对象的指针, 用于获取主题对象的信息来更新自己的状态。
c++ 代码
class Observer;
class Subject
{
public:
virtual void attach(Observer*) = 0;
virtual void detach(Observer*) = 0;
virtual void notify() = 0;
protected:
std::list<Observer*> observerList;
};
class Observer
{
public:
virtual Observer(Subject* sub): subject(sub){};
virtual void update() = 0;
protected:
Subject* subject;
};
class ConcreteSubject: public Subject
{
public:
void attach(Observer*) ;
void detach(Observer*) ;
void notify();
void setStatus(const string&);
string getStatus();
private:
string status;
};
void ConcreteSubject::attach(Observer* observer)
{
observerList.push_back(observer);
}
void ConcreteSubject::detach(Observer* observer)
{
observerList.remove(observer);
}
void ConcreteSubject::notify()
{
for(auto i : observerList)
{
observer->update();
}
}
void ConcreteSubject::setStatus(const string& s)
{
status = s;
}
string Concretesubject::getStatus()
{
return status;
}
class ConcreteObserver
{
public:
ConcreteObserver(Subject* sub):Observer(sub){};
void update(){
cout<<"updates: "<<subject->getStatus()<<endl;
};
};
变形
观察者对象中可以维护一个主题对象的指针, 这样的话, 观察者内部可以调用主题对象的函数获取信息(一个或者多个)来更新自己。 但这不是必须的。
另外一种选择是, 观察者对象不需要维护主题对象。 当主题对象状态发生改变时,主题对象调用notify()函数通知观察者对象, 此时可以将观察者需要的信息以参数的形式传给观察者的update(). 观察者根据参数来更新自己, 不需要拥有或者知道主题对象的存在。
拓展
在现实生活中, 一个观察者有可能同时观察两个或以上对象(两种不同的报纸, 或者一个报纸, 一个杂志), 这些主题对象可能是同一类, 也可能是不同类。 根据不同主题的变化, 观察者所需要更新的内容也不尽相同。 该如何设计?