目录 一、现实应用场景 二、初步实现 三、观察者模式 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()
,并规定了添加、移除和通知观察者的行为。 运行结果
五、更多
这个例子中需要在main
函数中手动调用注册,可以在Observer
对象创建时传入Subject
对象,以便自动注册。 详情请参阅 https://gitee.com/piglittle/design_patterns中的 Head_First_Design_Partterns
解决方案下的 observer_pattern
项目 其详细的类图如下