动机(Motivation)
- 在软件构建过程中,我们需要为某些对象建立一种“通知依赖关系”,——一个对象(目标对象)的状态发生改变,所有依赖对象(观察者对象)都将得到通知,如果这样的依赖关系过于紧密,将是软件不能很好地抵御变化。
- 使用面向对象技术,可以将这种依赖关系弱化,并形成一种稳定的依赖关系,从而实现软件结构的松耦合。
code
FileSplitter.cpp
class FileSplitter { string m_filePath; int m_fileNumber; 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++) { //.. } } };
MainForm.cpp
class MainForm :public Form
{
TextBox* txtFilePath;
TexBox* texFileNumber;
public:
void Button1_Click() {
string txtPath = txtFilePath->getText();
int number = atol(texFileNumber->getText().c_str());
FileSplitter splitter(filePath, number);
splitter.split();
}
};
上述代码存在的问题:
- 比如说需求变化,用户希望加一个进度条,来进行进度展示
修改后的代码:
FileSplitter.cpp
class FileSplitter
{
string m_filePath;
int m_fileNumber;
ProgessBar* m_progessBar;
public:
FileSplitter(const string& filePath, int fileNumber,
ProgessBar* progessBar) :
m_filePath(filePath),
m_fileNumber(fileNumber),
m_progessBar(progessBar)
{
//...
}
void split()
{
//1.读取大文件
//2.分批次向小文件中写入
for (int i = 0; i < m_fileNumber; i++)
{
//..
if (m_progessBar != nullptr)
{
m_progessBar->setValue((i + 1) / m_fileNumber);//更新进度条
}
}
}
};
mainForm.cpp
class MainForm :public Form
{
TextBox* txtFilePath;
TexBox* texFileNumber;
ProgessBar* progessBar;
public:
void Button1_Click() {
string txtPath = txtFilePath->getText();
int number = atol(texFileNumber->getText().c_str());
FileSplitter splitter(filePath, number, progessBar);
splitter.split();
}
};
存在的问题点:
违背的依赖倒置的原则,依赖具体实现细节。
继续修改
FileSplitter.cpp
class IProgess { public: virtual void DoProgess(float value) = 0; virtual ~Iprogess() {}; }; class FileSplitter { string m_filePath; int m_fileNumber; //ProgessBar* m_progessBar; List<Iprogress*> *m_iprogessList; //抽象通知机制,支持多个观察者 public: FileSplitter(const string& filePath, int fileNumber) : m_filePath(filePath), m_fileNumber(fileNumber) { //... } void add_IProgess(IProgess * iprogress){ m_iprogessList.push_back(iprogress); } void remove_IProgess(IProgess * iprogress) { m_iprogessList.remove(iprogress); } void split() { //1.读取大文件 //2.分批次向小文件中写入 for (int i = 0; i < m_fileNumber; i++) { //.. float progressValue = m_fileNumber; progressValue = (i + 1) / m_fileNumber; onProcess(progressValue); } } protected: void onProcess(float value) { List<IProgess*>::Iterator itor = m_iprogessList.begin(); while (itor != m_iprogessList.end() { m_iprogessList->DoProgess(progressValue);//更新进度条 itor++; } } } };
mainForm.cpp
class MainForm :public Form, public IProgess { TextBox* txtFilePath; TexBox* texFileNumber; ProgessBar* progessBar; public: void Button1_Click() { string txtPath = txtFilePath->getText(); int number = atol(texFileNumber->getText().c_str()); FileSplitter splitter(filePath, number); splitter.add_IProgess(this); splitter.add_IProgess(&cn); splitter.split(); splitter.remove_IProgess(this); } virtual void DoProgress(float value) { progessBar->setValue(value) } }; class ConsoleNotifer :public IProgess { public: virtual void DoProgress(float value) { cout << "."; } };