设计模式的作用:在变化和稳定之间寻找隔离点来分离他们从而来管理变化。因此全稳定和全变化的状态下都无设计模式可用。
“组件协作”模式:主要通过晚期绑定,来实现框架与应用程序之间的松耦合,是二者之间协作是常用的模式。
1.Template Method(模板方法)
动机:在软件构建过程中,对于某一项任务,他常常有稳定的整体操作结构,但各个子步骤却有很多改变的需求,或者由于固有原因而无法与任务的整体结构同时实现。
定义:定义一个操作中的算法的骨架(稳定),而将一些步骤延迟(变化)到子类中。Template Method使得子类可以不改变(复用)一个算法的结构即可重新定义(重写)该算法的某些步骤。
机制:虚函数的多态性
“不要调用我,让我来调用你”的反向控制结构是Template Method的典型应用。
在具体实现方面,被Template Method调用的虚方法可以有实现,也可以没有任何实现(纯虚方法),但一般把他们设置为protected方法(这些方法单独使用的意义并不大,往往要放到一个流程里才有意义,因此一般不给外界调用)。
举个栗子:
class library
{
public:
void Run()//固定流程
{
step1();
if (step2())//多态调用
{
step3();
}
step4();//多态调用
step5();
}
protected:
void step1();//稳定
void step3();//稳定
void step5();//稳定
virtual bool step2() = 0;//变化
virtual void step4() = 0;//变化
};
class application :public library
{
protected:
bool step2();//重写父类虚函数
void step4();//重写
};
int main()
{
library* p = new application();//基类实现,晚绑定
p->Run();//调用父类Run函数,其中的一些函数实现了多态调用
delete p;
}
2.Strategy(策略模式)
定义:定义一系列算法,把他们一个个封装起来,并且使他们可以互相替换(变化)。该模式使得算法可独立于使用他的客户程序(稳定)而变化(扩展,子类化)。
总结:Strategy及其子类为组件提供了一系列可重用的算法,从而可以使得类型在运行时方便地根据需要在各个算法之间进行切换。Strategy模式提供了用条件判断语句以外的另一种选择,消除判断语句,就是在解耦合。含有许多条件判断语句地代码通常需要Strategy模式。
若需要增加某个国家的税法计算,则只需要额外增加其他类的文件,不需要改变已有代码
class TaxStrategr
{
public:
virtual double Calculate() = 0;
virtual ~TaxStrategr(){}
};
class CNTax :public TaxStrategr
{
public:
double Calculate(){}
};
class USTax :public TaxStrategr
{
public:
double Calculate(){}
};
class Sales
{
private:
TaxStrategr* tax;
public:
~Sales() {
delete tax;
}
Sales(Factory* factory)
{
this->tax = factory->NewStrategy;
}
double Calculate()
{
double val = tax->Calculate;
}
};
3.Observer/Event(观察者模式)
定义:定义对象间地一对多(变化)的依赖关系,以便当一个对象的状态发生改变时,所有依赖它的对象都得到通知并自动更新。
总结:使用面向对象的抽象,Observer模式使得我们可以独立的改变目标与观察者,从而使二者之间的依赖关系达致松耦合。目标发送通知时,无需指定观察者,通知(可携带通知信息作为参数)会自动传播。观察者自己决定是否要订阅通知,目标对象对此一无所知。
以下的例子对于改变显示文件进度的方式,只需要改变主界面的内容,增加或减少方式,而不需要改变文件。
(注释掉的部分是开始一般思路)
file.cpp
class IProgress
{
public:
virtual void DoProgress(float value) = 0;
virtual ~IProgress(){}
};
class FileSplitter
{
string m_filePath;
int m_fileNumber;
//ProgressBar* m_progressBar;//具体通知控件
list<IProgress*> m_iprogressList;//通知抽象机制,支持多个观察者
public:
//FileSplitter(const string& filePath,int fileNumber, ProgressBar* progressBar):
FileSplitter(const string& filePath, int fileNumber) :
m_filePath(filePath),
m_fileNumber(fileNumber)
//m_progressBar(progressBar)
{}
void addIProgress(IProgress* iprogress)//增加显示文件进度方式
{
m_iprogressList.add(iprogress);
}
void remove_IProgress(IProgress* iprogress)//去除显示文件进度方式
{
m_iprogressList.remove(iprogress);
}
void split()
{
//1.读取大文件
//2.分批次向小文件中写入
for (int i = 0; i < m_fileNumber; ++i)
{
float progressValue = m_fileNumber;
progressValue = (1 + i) / progressValue;
onProgress(progressValue);//显示文件进度
}
}
protected:
virtual void onProgress(float value)
{
list<IProgress*>::iterator it=m_iprogressList.begin();
while (it != m_iprogressList, end())
{
it->DoProgress(value);//更新进度条
++it;
}
}
};
window.cpp
//文件分割器
//class MainForm : public From//主界面
class MainForm : public From,public IProgress//可以多继承接口,一般情况下不支持多继承
{
TextBox* txtFilePath;
TextBox* txtFileNumber;
ProgressBar* progressBar;//一种进度显示方式
public:
void Buttonl_Click()
{
string filePath = txtFilePath->getText();
int number = atoi(txtFileNumber->getText().c_str());
ConsoleNotifier cn;
//FileSplitter splitter(filePath, number, progressBar);
FileSplitter splitter(filePath, number);
splitter.addIProgress(this);//加入第一种显示
splitter.addIProgress(&cn);//第二种显示
splitter.split();//开始分割文件
splitter.removeIProgress(this);//去除第一种显示
}
void Doprogress(float value)
{
progressBar->setValue(value);
}
};
class ConsoleNotifier :public IProgress
{
public:
void Doprogress(float value)//第二种进度显示方式
{
cout << ".";
}
};
以上所有代码均为不可运行的伪代码,只为说明某个模式。