前提:组件协作模式

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

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

模板方法模式(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. Win10 打开 ubuntu子系统

    1. 修改windows的设置, 增加开发人员模式 针对开人员模式 使用添加删除程序 添加 ubuntu子系统的角色 运行输入control.. 然后添加删除程序 安装完后重启 运行输入 bash 就 ...

  2. number (2)变量相关错误

    变量没有被定义 fw cannot be resolved 变量没有被初始化 正确代码 package com.itheima_01; import java.io.FileWriter;import ...

  3. Java微信二次开发(六)

    Token定时获取 需要导入库:添加log4j(slf4j-api-1.5.10.jar,slf4j-log4j12-1.5.10.jar,log4j-1.2.15.jar,并且在src下添加log4 ...

  4. js screen

    windows.screen對象包含包含對象屏幕的信息: screen.availheight;屏幕高度 screen.availwidth;屏幕寬度

  5. Bootstrap自动定位浮标

    前面的话 Affix 插件主要功能就是通过插件给某个元素(需要固定的元素)添加或删除position:fixed,实现元素在浏览器窗口的粘性固定效果.本文将详细介绍Bootstrap自动定位浮标 基本 ...

  6. ansible系列1-批量分发钥匙

    auth.yaml- hosts: all gather_facts: false tasks: - name: deliver authorized_keys authorized_key: use ...

  7. BZOJ2938[Poi2000]病毒——AC自动机

    题目描述 二进制病毒审查委员会最近发现了如下的规律:某些确定的二进制串是病毒的代码.如果某段代码中不存在任何一段病毒代码,那么我们就称这段代码是安全的.现在委员会已经找出了所有的病毒代码段,试问,是否 ...

  8. JavaScript——根据数组中的某个值进行排序

    我这里是根据次数进行倒叙,可根据自己情况进行修改 function sortKey(array,key){ return array.sort(function(a,b){ var x = a[key ...

  9. matplotlib 28原则

    记下各个简易模板,方便ctrl+c和ctrl+v 子图: import numpy as np import matplotlib.pyplot as plt x = np.array(range(1 ...

  10. Python数据类型(列表和元组)

    1.3 List(列表) 列表由一系列按特定顺序排列的元素组成. 在Python中,用方括号[ ]来表示列表,并用逗号来分隔其中的元素. 1.3.1 访问列表元素 在Python中,第一个列表元素的索 ...