C++设计模式
整理自李建忠老师的《C++设计模式》视频教程
Observer观察者模式(常用)(组件协作模式)
“组件协作”模式:
现代软件专业分工之后的第一个结果是“框架与应用程序的划分”,“组件协作”模式通过晚期绑定,来实现框架与应用程序之间的松耦合,是二者之间协作时常用的模式。
- 典型模式
- Template Method
- Strategy
- Observer / Event
1. 动机(Motivation)
在软件构建过程中,我们需要为某些对象建立一种“通知依赖关系”:一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知。如果这样的依赖关系过于紧密,将使软件不能很好地抵御变化。
使用面向对象技术,可以将这种依赖关系弱化,并形成一种稳定的依赖关系。从而实现软件体系结构的松耦合。
2. 模式定义
定义对象间的一种一对多(变化)的依赖关系,以便当一个对象(Subject)的状态发生改变时,所有依赖于它的对象都得到通知并自动更新。——《设计模式》GoF
3. 结构(Structure)
4. 代码
文件分割器
4.1代码1
//--------------------------class MainForm---------------------------------//
class MainForm : public Form
{
TextBox *txtFilePath; //大文件的路径
TextBox *txtFileNumber; //分成几份
ProgressBar *progressBar; //观察者 //如:进度条显示
public:
void Button1_Click()
{
//收集参数信息
string filePath = txtFilePath->getText();
int number = atoi(txtFileNumber->getText().c_str());
//参数传递给FileSplitter
FileSplitter splitter(filePath, number, progressBar); //传递给下一级
//调用FileSplitter的split()方法
splitter.split();
}
};
//--------------------------class FileSplitter---------------------------------//
class FileSplitter
{
string m_filePath;
int m_fileNumber;
//此处违背了:依赖倒置原则
// 此处的实现细节,应该依赖于抽象
ProgressBar *m_progressBar; //依赖于上一级,所以要解决这种依赖关系
//具体的通知控件
public:
FileSplitter(const string &filePath,
int fileNumber,
ProgressBar *progressBar)
: m_filePath(filePath),
m_fileNumber(fileNumber),
m_progressBar(progressBar)
{
}
void split()
{
//1.分批次读取大文件
//2.分批次向小文件中写入
for (int i = 0; i < m_fileNumber; i++)
{
//...
float progressValue = m_fileNumber;
progressValue = (i + 1) / progressValue;
m_progressBar->setValue(progressValue);//更新进度条
}
}
};
//-----------------------------------------------------------//
4.2改进后的C++伪代码
-
01-依赖倒置原则(DIP)
- 高层模块(稳定)不应该依赖于低层模块(变化),二者都应该依赖于抽象(稳定) 。
- 抽象(稳定)不应该依赖于实现细节(变化) ,实现细节应该依赖于抽象(稳定)。
-
什么是依赖(编译时依赖)?
- A依赖B,A编译时B必须存在才能编译通过
//-----------------------class IProgress------class MainForm------------------------------//
//观察者 - 基类
class IProgress
{
public:
virtual void DoProgress(float value) = 0;
virtual ~IProgress() {}
};
// MainForm 是一个观察者 - 子类
class MainForm : public Form, public IProgress
{
TextBox *txtFilePath;
TextBox *txtFileNumber;
public:
void Button1_Click()
{
string filePath = txtFilePath->getText();
int number = atoi(txtFileNumber->getText().c_str());
ConsoleNotifier cn;
//此class的对象负责:分隔文件为几份
FileSplitter splitter(filePath, number);
splitter.addIProgress(this); //订阅通知//自身是一个观察者
splitter.addIProgress(&cn); //订阅通知//另一个观察者(每一个观察者决定自己是否订阅通知)
//函数功能:分隔文件
//分隔文件时,更新进度条,这个时候所有订阅者都要能收到通知
splitter.split();
splitter.removeIProgress(this); //删除一个观察者
}
//观察者:收到通知后的处理函数
//自身是一个观察者 - 子类
//自身作为观察者的处理函数--显示百分比
virtual void DoProgress(float value)
{
progressBar->setValue(value);
}
};
class ConsoleNotifier : public IProgress //另一个观察者
{
public:
// 此观察者对应的处理函数
// 不显示百分比,打点来显示进度
virtual void DoProgress(float value)
{
cout << ".";
}
};
//--------------------------class FileSplitter---------------------------------//
class FileSplitter
{
string m_filePath;
int m_fileNumber;
//ProgressBar *progressBar;//具体的通知控件
List<IProgress *> m_iprogressList;//抽象通知机制,支持多个观察者
//松耦合
//可以独立编译,不依赖 具体 某个进度通知
public:
FileSplitter(const string &filePath,
int fileNumber)
: m_filePath(filePath),
m_fileNumber(fileNumber){
}
void split()
{
//1.读取大文件
//2.分批次向小文件中写入
for (int i = 0; i < m_fileNumber; i++)
{
//...
float progressValue = m_fileNumber;
progressValue = (i + 1) / progressValue;
onProgress(progressValue); //给观察者-发送通知
}
}
public:
void addIProgress(IProgress *iprogress) //添加观察者,添加订阅
{
m_iprogressList.push_back(iprogress);
}
void removeIProgress(IProgress *iprogress) //移除某个观察者
{
m_iprogressList.remove(iprogress);
}
protected:
virtual void onProgress(float value){ // 给观察者-发送通知
List<IProgress *>::iterator itor = m_iprogressList.begin();
while (itor != m_iprogressList.end()){
(*itor)->DoProgress(value); //更新进度条
itor++;
}
}
};
//-----------------------------------------------------------//
C++不推荐多继承
只推荐一种多继承
一个是主要的基类,其它的都是接口(抽象基类)
5. 要点总结
- 使用面向对象的抽象,Observer模式使得我们可以独立地改变目标与观察者,从而使二者之间的依赖关系达致松耦合。
- 目标发送通知时,无需指定观察者,通知(可以携带通知信息作为参数)会自动传播。
- 观察者自己决定是否需要订阅通知,目标对象对此一无所知。
- Observer模式是基于事件的UI框架中非常常用的设计模式,也是MVC模式的一个重要组成部分。