观察者模式
定义了一种一对多的依赖关系,让多个观察者对象同时监听一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。
- Subject 类:主题或抽象通知类,一般用一个抽象类或者一个接口实现。它把所有对观察者对象的引用保存在一个聚集里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象。
Observer 类:抽象观察者,为所有的具体观察者定义一个接口,在得到主题的通知时更新自己。这个接口叫做更新接口。抽象观察者一般用一个抽象类或者一个接口实现。更新接口通常包含一个Update()方法
ConcreteSubject类 具体主题或具体通知者,将有关状态存入具体观察者对象;在具体主题的内部状态改变时,给所有登记过的观察者发出通知。具体主题角色通常用一个具体子类实现。
ConcreteObserver 类 具体观察者实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态相协调。具体观察者角色可以保存一个指向具体主题对象的引用。具体观察者角色通常用一个具体子类实现。
示例代码
//观察者模式
//Observer类 抽象观察者,为所有的具体观察者定义一个接口
class Observer
{
public:
virtual void Update() = 0;
};
//Subject类 主题或抽象的通知类
class Subject
{
public:
Subject(){ m_observers = new vector < Observer*> ; }
//增加观察者
void Attach(Observer *observer)
{
m_observers->push_back(observer);
}
//删除观察者
void Detach(Observer *observer)
{
cout << "从容器中将其删除函数" << endl;
}
//通知观察者
void Notify()
{
for (auto it = m_observers->begin(); it != m_observers->end(); ++it)
{
(*it)->Update();
}
}
private:
vector<Observer*> *m_observers; //由于Observer是抽象类所以不能实例化,所以容器里只能存放指向它的指针,所以这里需要特别注意
};
//ConcreteSubject类 具体主题或具体通知者
class ConcreteSubject: public Subject
{
public:
string Get_SubjectState(){ return m_subjectState; }
void Set_SubjectState(string state){ m_subjectState = state; }
private:
string m_subjectState;
};
//ConcreteObserver 类 具体观察者 实现抽象观察者角色所要求的更新接口,
class ConcreteObserver :public Observer
{
public:
ConcreteObserver(ConcreteSubject *subject, string name)
{
m_name = name;
m_subject = subject;
}
void Update()
{
m_observerState = m_subject->Get_SubjectState();
cout << "观察者{0}的新状态是{1} " << m_name <<" "<< m_observerState << endl;
}
ConcreteSubject* Get_Subject(){ return m_subject; }
void Set_Subject(ConcreteSubject* subject){ m_subject = subject; }
private:
string m_name;
string m_observerState;
ConcreteSubject *m_subject;
};
测试程序:
int main()
{
ConcreteSubject *Csubject = new ConcreteSubject;
//加入所要通知的对象
Csubject->Attach(new ConcreteObserver(Csubject, "X"));
Csubject->Attach(new ConcreteObserver(Csubject, "Y"));
Csubject->Attach(new ConcreteObserver(Csubject, "Z"));
//更新状态
Csubject->Set_SubjectState("ABC");
//进行通知
Csubject->Notify();
system("pause");
return 0;
}
观察者模式特点
- 将一个系统分割成一系列相互协作的类有一个很不好的副作用,那就是需要维护相关对象间的一致性。我们不希望为了维持一致性而是各类紧密耦合,这样会给维护、扩展和复用带来不变。
- 而观察者模式的关键对象是主题Subject 和观察者Observer,一个Subject可以有任意数目的依赖它的Observer,一旦Subject的状态发生改变,所有的Observer都可以得到通知。
- Subject发出通知时并不需要知道谁是它的观察者,也就是说,具体观察者是谁,它根本不需要知道。而任何一个具体观察者不知道也不需要知道其他观察者的存在。
何时使用观察者模式
- 当一个对象的改变要同时改变其他对象的时候,而且它不知道具体有多少对象有待改变时,应该考虑使用观察者模式。
- 当一个抽象模型有两个方面,其中一方面依赖于另一方面,,这时用观察者模式可以将这两者封装在独立的对象中使它们各自独立地改变和复用。
- 观察者模式所做的工作就是在接触耦合,让耦合的双方都依赖于抽象,而不依赖于具体。从而使得各自的变化都不会影响到另一边的变化。