目录
- 一、现实应用场景
- 二、初步实现
- 三、观察者模式
- 3.1 应用场景
- 3.2 详解
- 3.3 实现
- 3.4 设计类图
- 四、实现
一、现实应用场景
- 教师的手机号改变之后要通知给所有学生
- 如果有一个学生没有通知到位就会产生遗漏
- 如何自动完成
二、初步实现
2.1 实现方案1
- 定义学生和教师类
- 教师类设置set和get方法
- 教师的手机号修改后要依次调用所有学生的类重新设置
#include <iostream>class Student
{
private:std::string m_name;std::string m_tPhone;public:Student(const std::string& name){m_name = name;}void setTPhoneNubmer(const std::string& phone){m_tPhone = phone;}void show(){std::cout << "Name: " << m_name << " Teacher's Phone: " << m_tPhone << std::endl;}
};class Teacher
{
private:std::string m_phone;public:Teacher(const std::string& phone){m_phone = phone;}void setPhone(const std::string& phone){m_phone = phone;}std::string getPhone() const {return m_phone;}
};int main()
{Teacher zwz("12345");Student li("LiLei");Student Jie("Jie");Student wcz("wcz");li.setTPhoneNubmer(zwz.getPhone());Jie.setTPhoneNubmer(zwz.getPhone());wcz.setTPhoneNubmer(zwz.getPhone());li.show();Jie.show();wcz.show();zwz.setPhone("67890");li.setTPhoneNubmer(zwz.getPhone());Jie.setTPhoneNubmer(zwz.getPhone());wcz.setTPhoneNubmer(zwz.getPhone());li.show();Jie.show();wcz.show();return 0;
}
2.2 实现方案2
- 学生类中拥有一个教师的实例,该实例由外部传入
- 只要教师的手机号在外部修改,那个学生类中只需要通过
getPhone()
函数即可得到教师的手机号 - 实现过程如下
#include <iostream>class Teacher
{
private:std::string m_phone;public:Teacher(const std::string& phone){m_phone = phone;}void setPhone(const std::string& phone){m_phone = phone;}std::string getPhone() const{return m_phone;}
};class Student
{
private:std::string m_name;std::string m_tPhone;const Teacher* m_teacher;public:Student(const std::string& name, const Teacher* teacher){m_name = name;m_teacher = teacher;}void show(){std::cout << "Name: " << m_name << " Teacher's Phone: " << m_teacher->getPhone() << std::endl;}
};int main()
{Teacher zwz("12345");Student li("LiLei", &zwz);Student Jie("Jie", &zwz);Student wcz("wcz", &zwz);li.show();Jie.show();wcz.show();zwz.setPhone("67890");li.show();Jie.show();wcz.show();return 0;
}
- 存在问题
- 两个对象间存在紧耦合关系
- 如果换老师之后,老师的实例还得修改
- 缺少扩展性与灵活性
三、观察者模式
3.1 应用场景
- 当对象发生变化,
通知给其他对象
,需要其他对象做出调整 - 应用程序的
可维护性和重用性较高
- 互动关系不能体现成类之间的直接调用,对象之间关系的解耦
3.2 详解
- 观察者模式又称为发布订阅模式
- 两个角色: 观察者和被观察对象
- 两者之间存在”观察“的逻辑关联
- 当被观察者发生改变的时候,观察者就会观察到这样的变化,并且做出相应的响应
- 观察不是直接调用
- 实现观察者模式有很多形式,比较直观的一种是注册-> 通知 -> 撤销注册形式。
3.3 实现
- 步骤1:观察者将自己注册到被观察对象中,被观察对象将观察者存放在一个容器中。
- 步骤2:被观察者对象发生了某种变化,从容器中得到所有注册过的观察者,将变化通知观察者。
- 步骤3(可选):观察者告诉被观察者要撤销观察,被观察者从容器中将观察者去除。
3.4 设计类图

ConcreteSubject
: - 主题对象,被观察者,对应老师。
- 他有变化时通知
ConcreteObserver
类的实例(学生)。学生根据变化自动调用update()
做出响应。 - 内部有一个队列存储、移除观察者
- 当状态发生变化时可以调用
notifyObservers()
通知观察者
- 将
ConcreteSubject
与ConcreteObserver
类解耦 - 学生不只可以观察老师,还可以观察学院、某个同学等。
- 两个类分别向上抽取了被观察者接口
(Subject)
和观察者接口(Observer)
。
四、实现
#include <iostream>
#include <list>class IObserver
{
public:virtual void update(void* o) = 0;
};class ISubject
{
public:virtual void registerObserver(IObserver* obj) = 0;virtual void removeObserver(IObserver* obj) = 0;virtual void notifyObserver() = 0;
};class Teacher: ISubject
{
private:std::string m_phone;std::list<IObserver*> m_subject;public:void setPhone(const std::string& phone){m_phone = phone;notifyObserver();}std::string getPhone() const{return m_phone;}void registerObserver(IObserver* o){m_subject.push_back(o);}void removeObserver(IObserver* o){m_subject.remove(o);}void notifyObserver(){for (auto item : m_subject){item->update((void*)m_phone.c_str());}}
};class Student: public IObserver
{
private:std::string m_name;std::string m_tPhone;public:Student(const std::string& name){m_name = name;}void update(void* o){m_tPhone = reinterpret_cast<char*>(o);}void show(){std::cout << "Name: " << m_name << " Teacher's Phone: " << m_tPhone << std::endl;}
};int main()
{Teacher zwz;Student li("LiLei");Student Jie("Jie");Student wcz("wcz");Student test("test");zwz.registerObserver(&li);zwz.registerObserver(&Jie);zwz.registerObserver(&wcz);std::cout << "\n*******设置教师手机号为12345*******" << std::endl;zwz.setPhone("12345");li.show();Jie.show();wcz.show();zwz.removeObserver(&wcz); std::cout << "\n*******对教师手机号进行修改为67890*******" << std::endl;zwz.setPhone("67890");li.show();Jie.show();std::cout << "\n*******不会被改变*******" << std::endl;wcz.show(); return 0;
}
- 创建观察者接口
IObserver()
,并规定了更新的行为。 - 创建被观察者接口
ISubject()
,并规定了添加、移除和通知观察者的行为。 - 运行结果
