0 动机
在软件构件过程中,我们需要为某些对象建立一种“通过依赖关系”-----一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知。如果这样的依赖关系过于紧密,将使软件不能很好抵御变化。
使用面向对象技术,可以将这种依赖关系弱化,并形成一种稳定的依赖关系。从而实现软件体系结构的松耦
1 观察者模式定义
定义对象间的一种一对多(变化)的依赖关系,以便当一个对象(Subject)的状态发生改变时,所有依赖于它的对象都得到通知并自动更新。
按照自己理解,你向报社交了钱订了报纸,然后报社一有新报纸立马送到你家。这里报社其实就是一个被观察者(主题),而订报纸的人们就是观察者,这些观察者在报社里交了钱并登记(这里相当于观察者将自己放到报社中的一个list中),报社只知道这些订报纸人交了钱要给他们送报纸,其他一概不知(也就是,报社不知道这些人其他状态,也不知道这些人之间有啥关系),一当有新报纸打印出来,报社按照登记表一个个去送报纸。这样,每当或减一个订报人,登记表就多或少一个人。这里有个问题,当订报人订的报纸不一样或者订的数目不一样,这个模式就不行了,因为观察者都是统一的接口,大家要么都是钱江日报,要么都是光明日报,如果订报人订的报纸不一样,那么报社就要区分这些订报纸的人了,要弄2个登记表才OK。不然送报纸的人还要想这家人是订啥类型的报纸(观察者模式,报社是不知道观察者这些细节的)。
2 结构
3 代码
用送报纸来举例子有点老套了,换个有趣的例子。学校最近暑假在修水管,通知各所,暑假学生只能有一半留校。当听到这个消息后,有些人开心不已(暑假回家可以Happy),有些人十分惆怅(暑假回家了论文咋办,还要找工作呢),有些人则十分沮丧(凭啥我要留校科研,我也要出去玩)。这里每个学生就是具体观察者,而学校各所就是具体通知者(被观察者)。
//Stduent.h
#ifndef __STUDENT_OBSERVE__
#define __STUDENT_OBSERVE__
class Student
{
public:
Student(){};
virtual ~Student(){};
virtual void Update() = 0;
};
class HardStudent : public Student
{
public:
HardStudent(){};
~HardStudent(){};
void Update(){ printf("留校可以学到更多,开心!\n"); }
};
class LazyStudent : public Student
{
public:
LazyStudent(){};
~LazyStudent(){};
void Update(){ printf("我想出去玩,难过!\n"); }
};
#endif //__STUDENT_OBSERVE__
//College.h
#include "Student.h"
#include <list>
#ifndef __COLLEGE_SUBJECT__
#define __COLLEGE_SUBJECT__
class College
{
public:
College(){};
virtual ~College(){};
void RegisterObserve(Student *stduent){ m_observeArr.push_back(stduent); }
void DeleteObserve(Student *student);
void Notice();
private:
std::list<Student *> m_observeArr;
};
class Institute : public College
{
public:
Institute() : m_bStaySchool(false){};
~Institute(){};
void ReceiveMessage(bool bStay){ m_bStaySchool = bStay; }
void SendMessage();
private:
bool m_bStaySchool;
};
#endif //__COLLEGE_SUBJECT__
//college.cpp
#include "stdafx.h"
#include "College.h"
void College::DeleteObserve(Student *student)
{
for (auto i = m_observeArr.begin(); i != m_observeArr.end();)
{
if (*i == student)
{
i = m_observeArr.erase(i);
}
else
{
i++;
}
}
}
void College::Notice()
{
for (auto i = m_observeArr.begin(); i != m_observeArr.end(); i++)
{
(*i)->Update();
}
}
void Institute::SendMessage()
{
if (m_bStaySchool == true)
{
Notice();
}
}
//main
// main.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include "College.h"
#include "Student.h"
int main()
{
//创建实例
Institute institute;
Student *hard = new HardStudent();
Student *lazy = new LazyStudent();
//学生注册
institute.RegisterObserve(hard);
institute.RegisterObserve(lazy);
//给所发留校信息
institute.ReceiveMessage(true);
//通知学生
institute.SendMessage();
//lazy学生不开心要退学
institute.DeleteObserve(lazy);
//再次通知学生(这个时候只有hard学生了)
institute.SendMessage();
//释放内存
delete hard;
hard = nullptr;
delete lazy;
lazy = nullptr;
}
//输出结果
留校可以学到更多,开心!
我想出去玩,难过!
留校可以学到更多,开心!
请按任意键继续. . .
4 要点总结
- Observer模式使得我们可以独立地改变目标与观察者,从而使二者之间的依赖关系达致松耦合。
- 目标发送通知时,无需指定观察者,通知(可以携带通知信息作为参数)会自动传播。
- 观察者自己决定是否需要订阅通知,目标对象对此一无所知。
- Observer模式是基于事件的UI框架中非常常用的设计模式,也是MVC模式的一个重要组成部分。