前提:组件协作模式

现代软件专业分工之后的第一个结构是“框架应用程序的划分”,“组件协作”模式通过晚期绑定,来实现框架与应用程序之间的松耦合,是二者之间协作时常见的模式。
我们常常使用框架来写自己的应用,这样一个划分,必然中间需要有大量的协作问题。

典型模式(体现最为强烈,特征表现最为明显)

模板方法模式(Tempalte Method)
策略模式(Strategy)
观察者模式(Observer/Event)

一:模板方法模式(Tempalte Method)

(一)动机

在软件构建过程中,对于某一项任务,它常常有稳定的整体操作结构,但各个子步骤却有很多改变的需求,或者由于固有的原因(比如框架与应用之间的关系)而无法和任务的整体结构同时实现(必有一个早一个晚)
如何在确定稳定操作结构的前提下,来灵活应对各个子步骤的变化或者晚期实现需求

(二)原代码讲解(模拟流程)

1.程序库开发(框架开发)人员,其中实现了1,3,5步骤

//程序库开发人员
class Library{ public:
void Step1(){
//...
} void Step3(){
//...
} void Step5(){
//...
}
};

2.应用开发人员,我们需要实现2,4步骤

//应用程序开发人员
class Application{
public:
bool Step2(){
//...
} void Step4(){
//...
}
};
然后我们还需要具体的把这几个步骤以某种流程将其串起来
int main()
{
Library lib();
Application app(); lib.Step1(); if (app.Step2()){
lib.Step3();
} for (int i = ; i < ; i++){
app.Step4();
} lib.Step5(); }

3.总结

应用开发人员实现了部分应用程序步骤开发和程序的整体流程。
而这个流程既要调用到类库开发人员写的方法step1,step3,step5,同时还需要调用到应用程序开发人员(自己或协作者)写的step2,step4方法。
整体流程应该由框架设计人员为我们设定好,常常不需要我们更改,而且是稳定的

(三)改进版代码讲解(了解调用机制)

1.框架开发人员,直接为我们规定流程

//程序库开发人员
class Library{
public:
//稳定 template method
void Run(){ Step1(); if (Step2()) { //支持变化 ==> 虚函数的多态调用
Step3();
} for (int i = ; i < ; i++){
Step4(); //支持变化 ==> 虚函数的多态调用
} Step5(); }
virtual ~Library(){ } protected: void Step1() { //稳定
//.....
}
void Step3() {//稳定
//.....
}
void Step5() { //稳定
//.....
} virtual bool Step2() = 0;//变化
virtual void Step4() =0; //变化

};
由框架开发人员来为我们写出流程

2.应用开发人员,只需要实现步骤,和调用框架运行

//应用程序开发人员
class Application : public Library {
protected:
virtual bool Step2(){
//... 子类重写实现
} virtual void Step4() {
//... 子类重写实现
}
}; int main()
{
Library* pLib=new Application();  //多态指针
lib->Run();   delete pLib;  //注意上面,我们是使用的虚析构函数,是有必要的,若是不写成虚析构函数,我们就调用不了子类的析构函数,有可能出错,所以任何基类我们都应该写出析构函数,而且是虚析构函数
}
}

(四)两种形式比较

1.第一种是结构化软件设计流程

2.第二种是面向对象软件设计流程

(五)调用关系

1.第一种调用关系是:早绑定

2.第二种调用关系是:晚绑定

(六)早绑定和晚绑定

定义:

Library出现早,Application出现晚,晚的东西去调用早的东西就叫做早绑定,像C语言这类就是如此
Application出现晚,我们使用早的Library去调用早的东西就叫做晚绑定,面向对象语言都实现这种

或者:

当我们写完Application就实现了Run方法去调用library,所以很早就调用了,就是早绑定
而当我们使用第二种方法,我们实现了Application后,并不能直接运行,而是要有library去将两者绑定在一起,所以是晚绑定

(七)模式定义

定义一个操作中的算法的骨架<Run>(稳定),而将一些步骤延迟<定义一个虚函数,让子类去实现(重写)这个虚函数>(变化)到子类<支持子类来变化,我现在定不下来如何实现,让子类来实现>中。
Template Method使得子类可以不改变(复用)一个算法的结构即可重定义(override重写)该算法的某些特定步骤。
                                          ——《设计模式》GOF

1.第一种是结构化思想实现,Application实现较复杂

2.第二种是我们的模板方法模式,是改良后的,模板就是样板,我们的Run方法就是一个样板

复用Run方法

    //稳定 template method
void Run(){ Step1(); if (Step2()) { //支持变化 ==> 虚函数的多态调用
Step3();
} for (int i = ; i < ; i++){
Step4(); //支持变化 ==> 虚函数的多态调用
} Step5(); }

稳定中有变化(相对的)

Run方法就是稳定的,其中的虚函数step2,step4就是变化的。稳定的代码,我们要写成非虚函数,而支持变化的我们要写成虚函数

(八)在模式应用的时候:核心就是去分辨出来软件体系中哪些是稳定的哪些是变化的

相对稳定和相对变化,不讨论绝对,不然设计模式全不适用

(九)缺点

在我们使用C编写windows程序时,需要我们自己去写出流程,虽然麻烦但是了解更多。
但是对于面向对象模板方法模式的使用,框架是将流程隐藏在了library中,我们若是只实现了application,那么我们只是完成业务,而未了解流程,只见树木不见森林
显然,流程是一个核心,我们应该去了解library做了什么
随着我们能力提升,我们需要去实现library

(十)类图(角色和职责)

我们通过类图知道是在稳定点中去调用了变化点,其中并未写出step1,step2,step5等稳定点
我们在学习设计模式的时候最好通过类图去了解哪些是稳定的哪些是变化的,学会去画出类图

(十一)要点总结

.Template Mechod模式是一种非常基础性的设计模式,在面向对象系统中有着大量的应用。它用最简洁的机制(虚函数的多态性)为很多应用程序框架提供了灵活的拓展点,是代码复用方面的基本实现结构。
.除了可以灵活应对子步骤的变化外,“不要调用我,让我来调用你<晚绑定>”的反向控制结构是Template Method的典型应用。
.在具体实现方面,被Template Method调用的虚方法可以具有实现,也可以没有任何实现(抽象方法、纯虚方法),但一般推荐将它们设置为protected方法<单独作为一个方法暴露出去给人家调用时没有意义的,他往往放在一个流程中,才有意义>

(十二)应用场景

一般应用在具有以下条件的应用中:

.具有统一的操作步骤或操作过程
.具有不同的操作细节
.存在多个具有同样操作步骤的有场景,但某些具体的操作细节却各不相同

总结

在抽象类中统一操作步骤,并规定好接口,让子类实现接口,这样可以把各个具体子类和操作步骤解耦合

(十三)案例实现

#include <iostream>
using namespace std; class MakeCar
{
public:
void make()
{
makeHead();
makeBody();
makeTail();
} virtual ~MakeCar(){}
protected:
virtual void makeHead() = ;
virtual void makeBody() = ;
virtual void makeTail() = ;
};
class MakeBus :public MakeCar
{
public:
virtual void makeHead()
{
cout << "Bus install head" << endl;
} virtual void makeBody()
{
cout << "Bus install body" << endl;
} virtual void makeTail()
{
cout << "Bus install tail" << endl;
}
};
class MakeJeep :public MakeCar
{
public:
virtual void makeHead()
{
cout << "Jeep install head" << endl;
} virtual void makeBody()
{
cout << "Jeep install body" << endl;
} virtual void makeTail()
{
cout << "Jeep install tail" << endl;
}
};
void main()
{
MakeCar* bus = new MakeBus();
bus->make(); delete bus; MakeCar* jeep = new MakeJeep();
jeep->make(); delete jeep; cout << "test make car finished" << endl;
system("pause");
return;
}

设计模式---组件协作模式之模板方法模式(Tempalte Method)的更多相关文章

  1. 设计模式之第3章-模板方法模式(Java实现)

    设计模式之第3章-模板方法模式(Java实现) "那个,上次由于我老婆要给我做饭,所以就没有说完就走掉了...这个那个".这次和以前一样,先来开场福利(工厂方法模式已被作者踹下场) ...

  2. 简介Python设计模式中的代理模式与模板方法模式编程

    简介Python设计模式中的代理模式与模板方法模式编程 这篇文章主要介绍了Python设计模式中的代理模式与模板方法模式编程,文中举了两个简单的代码片段来说明,需要的朋友可以参考下 代理模式 Prox ...

  3. C#设计模式学习笔记:(13)模板方法模式

    本笔记摘抄自:https://www.cnblogs.com/PatrickLiu/p/7837716.html,记录一下学习过程以备后续查用. 一.引言 今天我们要讲行为型设计模式的第一个模式--模 ...

  4. Android设计模式之命令模式、策略模式、模板方法模式

    命令模式是其它很多行为型模式的基础模式.策略模式是命令模式的一个特例,而策略模式又和模板方法模式都是算法替换的实现,只不过替换的方式不同.下面来谈谈这三个模式. 命令模式 将一个请求封装为一个对象,从 ...

  5. 设计模式(十四)模板方法模式(Template Pattern)

    一.引言 提到模板,大家肯定不免想到生活中的“简历模板”.“论文模板”.“Word中模版文件”等,在现实生活中,模板的概念就是——有一个规定的格式,然后每个人都可以根据自己的需求或情况去更新它,例如简 ...

  6. Java进阶篇设计模式之十一 ---- 策略模式和模板方法模式

    前言 在上一篇中我们学习了行为型模式的访问者模式(Visitor Pattern)和中介者模式(Mediator Pattern).本篇则来学习下行为型模式的两个模式,策略模式(Strategy Pa ...

  7. 设计模式总结篇系列:模板方法模式(Template Method)

    模板方法模式需要开发抽象类和具体子类之间的协作.抽象类负责给出一个算法的轮廓和骨架,子类则负责给出这个算法的各个逻辑步骤.代表这些具体逻辑步骤的方法称做基本方法(primitive method):而 ...

  8. Java设计模式之十一 ---- 策略模式和模板方法模式

    前言 在上一篇中我们学习了行为型模式的访问者模式(Visitor Pattern)和中介者模式(Mediator Pattern).本篇则来学习下行为型模式的两个模式,策略模式(Strategy Pa ...

  9. 【设计模式】行为型02模板方法模式(Template Method Patten)

    五一长假,没有出去,不喜欢嘈杂的人群,玩了会游戏发泄了下憋在心底的戾气,手旁大马克杯里是母亲泡的绿茶.点开自己的播放列表,耳机里传来的是理查德克莱德曼的致爱丽丝.自己是个凡人,卑微渺小的活着.不说废话 ...

随机推荐

  1. msyql sql语句收集

    在不断的学习中,发现了一些新的slq语句,总结于此. 一.复制数据表的sql 1)create table tableName  as  select  * from   tableName2     ...

  2. MySQL下载安装详情教程

    1.下载MySQL数据库可以访问官方网站:https://www.mysql.com/ 2.点击DOWNLOADS模块下的Community模块下的MySQL Community Server进行下载 ...

  3. 在保存Bitmap的时候出现“GDI出现一般性错误”

    今天开发的时候出现过一个非常奇怪的问题,在保存最终的Bitmap图片的时候,明明使用Directory.Exist(filePath)函数判断当前路径的时候,这些路径都是有用的并且都是合法的,但是就是 ...

  4. Test Scenarios for sending emails

    (test cases for composing or validating emails are not included)(make sure to use dummy email addres ...

  5. loadrunner基础学习笔记二

    virtual user generator(vugen) 在测试环境中,loadrunner在物理计算机上使用vuser代替实际用户.vuser以一种可重复.可预测的方式模拟典型用户的操作,对系统施 ...

  6. C-Lodop回调函数的触发

    高版本的火狐和谷歌不再支持np插件之后,Lodop公司推出了C-Lodop,解决了这些浏览器不能用Lodop插件方式打印的问题,相比较Lodop插件,C-Lodop由于是以服务的形式出现,返回值不能直 ...

  7. std::shared_ptr 和普通指针的转换

    相互转化见示例 struct test { int num; string name; }; test* pTest = new test(); std::shared_ptr<test> ...

  8. mysql5.7 rpm安装教程

    注意版本和此次更新时间 2017-12-03  版本:mysql-5.7.20-1.el6.x86_64  环境:linux6.x ​官方下载地址: wget https://dev.mysql.co ...

  9. BZOJ1827[USACO 2010 Mar Gold 1.Great Cow Gathering]——树形DP

    题目描述 Bessie正在计划一年一度的奶牛大集会,来自全国各地的奶牛将来参加这一次集会.当然,她会选择最方便的地点来举办这次集会.每个奶牛居住在 N(1<=N<=100,000) 个农场 ...

  10. 安装Prometheus-Opeartor

    一.下载git clone clone https://github.com/coreos/prometheus-operator.git或:wget https://github.com/coreo ...