本系列所有文章来自李建忠老师的设计模式笔记,系列如下:
设计模式(一)面向对象设计原则
23种设计模式(二)组件协作之模板方法
23种设计模式(三)组件协作之策略模式
23种设计模式(四)组件协作之观察者模式
23种设计模式(五)单一职责之装饰模式
23种设计模式(六)单一职责之桥模式
23种设计模式(七)对象创建之工厂方法
23种设计模式(八)对象创建之抽象工厂
23种设计模式(九)对象创建之原型模式
23种设计模式(十)对象创建之构建器
23种设计模式(十一)对象性能之单件模式
23种设计模式(十二)对象性能之享元模式
23种设计模式(十三)接口隔离之门面模式
23种设计模式(十四)接口隔离之代理模式
23种设计模式(十五)接口隔离之适配器
23种设计模式(十六)接口隔离之中介者
23种设计模式(十七)状态变化之状态模式
23种设计模式(十八)状态变化之备忘录
23种设计模式(十九)数据结构之组合模式
23种设计模式(二十)数据结构之迭代器
23种设计模式(二十一)数据结构之职责链
23种设计模式(二十二)行为变化之命令模式
23种设计模式(二十三)行为变化之访问器
23种设计模式(二十四)领域规则之解析器
文章目录
- Template Method 模式
- 设计方法一
- 设计方法二
- 两种方法对比
- 模式定义
23种设计模式主要可以分为以下几类:
- 从目的来看:
创建型(Creational)模式:将对象的部分创建工作延迟到子类或者其他对象,从而应对需求变化为对象创建时具体类型实现引来的冲击。
结构型(Structural)模式:通过类继承或者对象组合获得更灵活的结构,从而应对需求变化为对象的结构带来的冲击。
行为型(Behavioral)模式:通过类继承或者对象组合来划分类与对象间的职责,从而应对需求变化为多个交互的对象带来的冲击。
- 从范围来看:
类模式处理类与子类的静态关系。
对象模式处理对象间的动态关系。
- 从封装变化角度对模式分类
面向对象设计模式是“好的面向对象设计”,所谓“好的面向对象设计”指是那些可以满足“应对变化,提高复用”的设计。
现代软件设计的特征是“需求的频繁变化”。设计模式的要点是“寻找变化点,然后在变化点处应用设计模式,从而来更好地应对需求的变化”.“什么时候、什么地点应用设计模式”比“理解设计模式结构本身”更为重要。
不光是写代码,看代码也需要看到代码的变化部分,与不变部分。
设计模式的应用不宜先入为主,一上来就使用设计模式是对设计模式的最大误用。没有一步到位的设计模式。敏捷软件开发实践提倡的“Refactoring to Patterns”(重构设计模式)是目前普遍公认的最好的使用设计模式的方法。
Template Method 模式
在软件构建过程中,对于某一项任务,它常常有稳定的整体操作结构,但各个子步骤却有很多改变的需求,或者由于固有的原因(比如框架与应用之间的关系)而无法和任务的整体结构同时实现。
设计方法一
先举个例子看一下:
- template1_lib.cpp
//程序库开发人员
class Library{
public:
void Step1(){
//...
}
void Step3(){
//...
}
void Step5(){
//...
}
};
- template1_app.cpp
//应用程序开发人员
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();
}
上述的main
函数执行的流程常常是不需要更改且是稳定的。
上面是一种做法,接下来看一下第二种做法:
设计方法二
- template2_lib.cpp
//程序库开发人员
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; //变化
};
这里的框架开发人员完全可以把这个主函数的流程给写下来。
- template2_app.cpp
//应用程序开发人员
class Application : public Library {
protected:
virtual bool Step2(){
//... 子类重写实现
}
virtual void Step4() {
//... 子类重写实现
}
};
int main()
{
Library* pLib=new Application();
lib->Run();
delete pLib;
}
}
Library* pLib=new Application();
是一个多态指针,他的声明类型是一个Library
, 但是实际类型是Application
,当它调用虚函数的时候就会按照虚函数的动态绑定规则去调用。
在c++
里面写一个基类的话,有一条原则就是应该把这个基类里面的析构函数写成虚的。如果不写成虚的,那么Library* pLib=new Application();
这行代码就调用不到子类的析构函数。
两种方法对比
第一种方法是结构化的软件设计流程
- 结构化软件设计流程
- 面向对象软件设计流程
这两种设计方法主要的不同之处在于早绑定与晚绑定:
Library
一般写地早,Application
写地比较晚,当一个写地比较晚的东西调用一个写地比较早的东西,这就是早绑定。这是所有编程语言都比较默认的做法。在面向对象编程里面有一种叫做晚绑定的机制,Library
调用Application
, 一个早的东西调用一个晚的东西,这就叫做晚绑定。
模式定义
定义一个操作中的算法的骨架(稳定),而将一些步骤延迟(变化)到子类中。Template Method
使得子类可以不改变(复用)一个算法的结构即可重定义(override
重写)该算法的某些特定步骤。
通俗一点来说就是定义一个虚函数,让子类去实现这个虚函数。延迟到子类也就是支持子类变化。
最后
以上就是等待百合最近收集整理的关于23种设计模式(二)组件协作之模板方法的全部内容,更多相关23种设计模式(二)组件协作之模板方法内容请搜索靠谱客的其他文章。
发表评论 取消回复