设计模式C++001__模板方法
“组件协作”模式:
现代软件专业分工之后的第一个结果就是“框架与应用程序的划分”,组件“协作”模式通过晚绑定,来实现框架与应用程序之间的松耦合。
包括:
模版方法,观察者模式,策略模式
1、模板方法模式:
动机:在软件构建过程中,对于一项任务,它常常有稳定的整体操作结构,但各个子步骤却有很多改变的需求,或者由于固定的原因(比如框架与应用之间的关系)而无法和任务的整体结构同时实现。
如何在稳定操作结构的前提下,来灵活应对各个子步骤的变化或者晚期实现需求。
从静态编译的角度看,结构化软件设计流程是符合人们的直觉的,先开发好类库或者库函数。然后我们业务开发的程序员来调用Lib库中的函数。
但是一般库函数是稳定的,业务变更频繁,不同业务对2、4步骤实现会千差万别。
图中红色部分是稳定部分,类库一旦写好,核心功能基本确定。整体系统的运行还需要根据具体业务填充蓝色部分2、4步骤。我们做开发时要想到设计模式的原则:
依赖倒置原则,即上层不应该依赖底层。这里1,3,5就是底层实现,2,4所在的Application是上层业务层。那么我们应该1,3,5依赖2,4所在Application。
即细节应该依赖抽象,而不是抽象依赖细节。
在面向开发过程中,由于有多态的特性,或者类似其他语言运行时的支持,例如C++的多态特性,C语言的函数指针,OC的runtime。一些函数的调用关系被放到了运行时才确定。
这样,就可以将一些步骤延迟到子类,或者运行时来做。
这里就引出了早绑定和晚绑定的概念。正是因为有了晚绑定的概念,库和业务程序之间这种跨时间维度的开发交互成为现实。
库的开发人员只需要知道,2,4步骤将来一定会由外部业务开发人员来实现。我只需要开发好1,3,5.并把调用整体流程的框架搭好就行了。
2、早绑定和晚绑定
//C语言中的函数调用,编译期就已经确定好调用关系-----早绑定
#import <stdio.h>
void printHello(){
printf("Hello, world!");
}
void printGoodBye(){
printf("Goodby, world!");
}
void doSomeThing(int type){
if(type == 0){
printHello();
}else{
printGoodbye();
}
}
//C语言中 运行时才确定好调用关系 ----晚绑定
#import <stdio.h>
void printHello(){
printf("Hello, world!");
}
void printGoodBye(){
printf("Goodby, world!");
}
void doSomeThing(int type){
void (*func)();//声明一个函数指针,
if(type == 0){
func = printHello;
}else{
func = printGoodbye;
}
func();//这个函数调用的指令,不过待调用的函数地址无法硬编码在指令中,只有在运行时读出来。
}
以结构化的程序开发流程为例:
//lib库的开发
//程序库开发人员
class Library{
public:
void Step1(){
//...
}
void Step3(){
//...
}
void Step5(){
//...
}
};
//Application的开发
//应用程序开发人员
class Application{
public:
bool Step2(){
//...
}
void Step4(){
//...
}
};
int main()
{
Library lib();
Application app();
lib.Step1();
if (app.Step2()){
lib.Step3();
}
for (int i = 0; i < 4; i++){
app.Step4();
}
lib.Step5();
}
面向对象的开发流程
//程序库开发人员
class Library{
public:
//稳定 template method
void Run(){
Step1();
if (Step2()) { //支持变化 ==> 虚函数的多态调用
Step3();
}
for (int i = 0; i < 4; i++){
Step4(); //支持变化 ==> 虚函数的多态调用
}
Step5();
}
virtual ~Library(){ }
protected:
void Step1() { //稳定
//.....
}
void Step3() {//稳定
//.....
}
void Step5() { //稳定
//.....
}
virtual bool Step2() = 0;//变化
virtual void Step4() =0; //变化
};
主程序的开发
//应用程序开发人员
class Application : public Library {
protected:
virtual bool Step2(){
//... 子类重写实现
}
virtual void Step4() {
//... 子类重写实现
}
};
int main()
{
Library* pLib=new Application();
lib->Run();
delete pLib;
}
}
3、模板方法模式的定义:
定义一个操作中的算法骨架(稳定),而将一些步骤(变化)延迟到子类中。Template Method使得子类可以不改变(复用)一个算法的结构即可重定义(override)该算法的某些特定步骤。--GoF
结构:
4、要点:
Template Method模式是一种非常基础的设计模式,在面向对象系统中有着大量的应用。它用最简洁的机制(虚函数多态特性)为很多应用程序框架提供了灵活的扩展点,是代码复用方面的基本实现结构。
除了可以灵活应对子步骤的变化外,“不要调用我,让我来调用你”的反向控制结构式Template Method的典型应用。
在具体实现方面,被Template Method调用的虚方法可以具有实现,也可以没有任何实现(抽象方法,纯虚方法),但一般不推荐将他们设置为protected方法。