关于观察者模式,对它的认知依旧是起源于菜鸟教程的设计模式篇章,里面解释的很到位。
这里简单介绍一句,当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)。比如,当一个对象被修改时,则会自动通知它的依赖对象。观察者模式属于行为型模式。详细介绍戳该链接——菜鸟教程~观察者模式
本文分享一个老师布置作业的例子
感觉这个例子完美诠释了观察者模式,学生作为观察者,观察者模式的设计可以让老师在布置作业后,自动通知到每个选了该老师课的学生,话不多说,先上个UML图。
然后再上个代码吧
student.h
#ifndef _STUDENT_
#define _STUDENT_
#include "iostream"
#include "string"
#include "list"
#include "teacher.h"
using namespace std;
class teacher;
class student
{
protected:
string m_homework;
public:
student(){}
virtual string get_content() = 0; //获取作业内容
virtual void update_content() = 0; //更新作业内容
};
class programming_stu:public student
{
private:
string m_name; //学生名字
teacher *m_t; //该学生的老师
public:
programming_stu(string name, teacher *t):m_name(name),m_t(t){}
~programming_stu();
string get_content();
void update_content();
};
#endif
student.cpp
#include "student.h"
#include "teacher.h"
#include "iostream"
#include "string"
#include "list"
using namespace std;
string programming_stu::get_content()
{
return m_homework;
}
void programming_stu::update_content()
{
m_homework = m_name + ":" + m_t->get_content();
return;
}
teacher.h
#ifndef _TEACHER_
#define _TEACHER_
#include "iostream"
#include "string"
#include "student.h"
#include "list"
using namespace std;
class student;
class teacher
{
private:
list<student*> m_observers; //记录老师的所有学生
protected:
string m_homework; //家庭作业内容
public:
virtual void set_content(string content) = 0;
virtual string get_content() = 0;
void add_stu(student *stu);
void dec_stu(student *stu);
void notify_stu();
};
class programming_teacher:public teacher
{
private:
string m_name;
public:
programming_teacher(string str_name):m_name(str_name){}
~programming_teacher();
void set_content(string str_homework);
string get_content();
};
#endif
teacher.cpp
#include "student.h"
#include "teacher.h"
#include "iostream"
#include "string"
#include "list"
using namespace std;
void teacher::add_stu(student *stu)
{
m_observers.push_back(stu);
}
void teacher::dec_stu(student *stu)
{
m_observers.remove(stu);
}
void teacher::notify_stu()
{
list<student*>::iterator it_stu;
for (it_stu=m_observers.begin(); it_stu!=m_observers.end(); it_stu++)
{
(*it_stu)->update_content();
}
}
void programming_teacher::set_content(string str_homework)
{
m_homework = "The assignment " + m_name + " arranged is " + str_homework;
notify_stu();
}
string programming_teacher::get_content()
{
return m_homework;
}
observers_mode.cpp
#include "teacher.h"
#include "student.h"
#include "iostream"
#include "string"
using namespace std;
int main(int argc, char const *argv[])
{
teacher *lzl = new programming_teacher("lzl");
student *hk = new programming_stu("hk", lzl);
student *gg = new programming_stu("gg", lzl);
lzl->add_stu(hk);
lzl->add_stu(gg);
lzl->set_content("learn c++");
cout << hk->get_content() << endl;
lzl->dec_stu(hk);
lzl->set_content("learn linux");
cout << gg->get_content() << endl;
cout << hk->get_content() << endl;
if (lzl != NULL)
{
delete lzl;
lzl = NULL;
}
if (hk != NULL)
{
delete hk;
hk = NULL;
}
if (gg != NULL)
{
delete gg;
gg = NULL;
}
return 0;
}
输出结果
最后分享一个C++小知识
写这个demo的时候还真是各种问题齐飞呀,一开始写完编译的时候各种未定义报错。原因是student和teacher这两个类需要相互引用,总之就是两个类如果要相互引用的话像我上面这样写就对了。
两个类相互引用,不管哪个类在前面,都会出现有一个类未定义的情况,所以可以提前声明一个类,而类的声明就是提前告诉编译器,所要引用的是个类,但此时后面的那个类还没有定义,因此无法给对象分配确定的内存空间,因此只能使用类指针,不能引用实体对象。