设计模式2-观察者模式

05/08/2020
05/09/2020 大话设计模式中的观察者模式

回顾设计模式1

组合和继承

回顾上一个策略,鸭子类中有飞行行为和叫声行为,红鸭子,玩具鸭等其他玩具鸭子类继承鸭子类。
在这里有两个关键字

  • 有一个:鸭子类有飞行行为,表示组合(composition)
  • 是一个:红鸭子是鸭子,表示继承

有时候组合比继承更好

多用组合,少用继承。

策略模式- 模拟鸭子类

定义了算法族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化独立于使用算法的客户

心得

  • 面向对象的学习:在于如何复用,比如继承

OO基础

  • 抽象
  • 封装
  • 多态
  • 继承

OO原则

有一些面向对象原则,适用于所有的模式。但是不一定有适当的模式解决问题。

  1. 封装变化
  2. 多用组合,少用继承
  3. 针对接口编程,不针对实现编程

OO模式

  • 策略模式
  • 简单工厂
  • 。。。

观察者模式(Observer)

观察者模式定义了对象之间一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会受到通知并自动更新。

例如:报纸订阅服务,有一个出版者对象对应多个订阅者对象。订阅者依赖出版者。出版者更新并通知给所有订阅者更新。

松耦合

当两个对象之间松耦合,它们依然可以交互,但是不太清楚彼此的细节。

设计原则4

为了交互对象之间的松耦合设计而努力。

案例:气象站与布告栏模拟

基本属性

气象站:

  • 温度
  • 湿度
  • 大气压力
    多个布告栏:
  • 根据气象站的信息,显式不同的状态
  • 当前布告栏:显式温度,湿度,大气压力
  • 天气预报布告栏:显式温度与湿度的占比多少,决定当前的天气状况

一对多关系,一对应Subject类,多对应Observer类. 它们之间相互拥有对方的类。

第一个问题

C++中如何解决相互引入头文件问题。
C++前向声明解决方案

主题接口与观察者接口

//interface
class Subject
{
public:
	//主题可以增减通知观察者们
	virtual void registerObserver(Observer o) =0; 
	virtual void removeObserver(Observer o) = 0;
	virtual void notifyObservers() = 0;
};

//interface 
class Observer //所有观察者继承这个接口,来实现update方法,来更新
{
public:
	virtual void update(float temp, float humidity, float pressure) = 0;
};

//interface
class DisplayElement
{
public:
	virtual void display() = 0;
};

继承主题接口的对象

class WeatherData: public Subject
{
public:
	WeatherData()
	{
		observers = new std::list<Observer>
	}
	void registerObserver(Observer* o)override
	{
		observers.push_back(o);
	}
	void removeObserver(Observer* o)override
	{
		//for-loop to erase observer
	}
	void notifyObservers()override
	{
		for(auto& x: Observers)
		{
			x->update(mTemperator,mHumidity,mPressure);
		}
	}
	void measurementsChanged()
	{
		notifyObservers();
	}
	void setMeasurements(float temperature, float humidity, 
						 float pressure)
	{
		mTemperature = termperature;
		mHumidity = humidity;
		mPressure = pressure;
		measurementsChanged();
	}
private:
	std::list<Observer*>* observers;
	float mTemperature;
	float mHumidity;
	float mPressure;
};

布告栏继承观察接口

class CurrentConditionDisplay: public Observer,public DisplayElement
{
public:
	CurrentConditionDisplay(Subject* weatherData)
	{
		this->weatherData = weatherData;
		weatherData->registerObserver(this);
	}
	void update(float temperature, float humidity,
				float pressure)override
	{
		mTemperature = temperature;
		mHumidity = humidity;
		mPressure = pressure;
		display();
	}
	void display()override
	{
		//print private info.
	}
private:
	float mTemperature;
	float mHumidity;
	float mPressure;
	Subject* weatherData; //有一个公共的主题对象
};

气象站运行

int main()
{
WeatherData* weatherData = new WeatherData; //主题

//观察者们
CurrentConditionDisplay* currentDisplay = new CurrentConditionDisplay(weatherData);
StatisticsDisplay* statisticsDisplay = new StatisticsDisplay(weatherData);
OtherDisplay* otherDisplay = new OtherDisplay(weatherData);

//通知观察者们
weatherData.setMeasurements(80.0,65.0,30.4);
weatherData.setMeasurements(23.4,53.7,30.4);

}

Java中自带的Observable

Observable并没有实现接口编程,而是把主题接口变成一个超类。

大话中的观察者模式

模拟关于老板通知问题

通常在学校上自习课的时候,坐在门口的同学如果发现老师来了,通常会通知同桌,继而教室也会变得安静许多。一旦老师走了,教室又会变得吵闹。老师来没来的状态与班级的状态相互联系。

双向耦合

class Teacher
{
public:
	void attach(Student* student); //mStudentsList->push_back(student)
	void notify()
	{
		for(auto x:mStudentsList)
		{
			x->update();
		}
	}
	
	//get/set function for teacherAction
private:
	std::list<Student*> mStudentsList;
	std::string teacherAction; //老师的状态,来没来
};

class Student
{
public:
	Student student(std::string name,Teacher* teacher):
	mName(name),
	mTeacher(teacher)
	{}
	void update()
	{
		std::cout << mName<<"停下讲话,去做作业"; //耦合所在,不是所有的学生都在讲话,有可能其他学生在听音乐
	}
	
private:
	std::string mName;
	Teacher* mTeacher; //班主任相同
};

问题

  1. 这个是个双向耦合问题,有常量输出的地方就很难扩展,观察的同学不一定都在讲话,有可能在忙些别的事情,比如听音乐,睡觉等。
  2. 来的不一定是老师,如果换成校长也应该通知给所有的观察者们。

动机

  • 将一个系统分割成一系列相互协作的类有一个很不好的副作用,那就是需要维护相关对象间的一致性。
  • 一旦主题对象发生状态改变,其他观察者们都可以得到通知。

使用

  • 当一个对象的改变需要同时改变其他对象的时候,并且主题对象不需要知道具体有多少对象有待改变
  • 解除耦合。让耦合的双方都依赖于抽象,而不是依赖于具体。从而各自的变化不会影响另一边的变化。
  • 依赖倒转原则的体现

Head First Design Pattern: Observer pattern
大话设计模式第14章

猜你喜欢

转载自blog.csdn.net/weixin_44200074/article/details/105976922