一、定义

定义一个操作中的框架,而将一些步骤延迟到子类中。使得子类可以不改变逻辑的情况下即可重定义该算法的某些特定步骤。

二、栗子

1、模板方法模式(通用版)

(1)UML图

(2)UML说明

AbstractClass 叫抽象模板,其方法分为两类:

基本方法:即基本操作,是由子类实现的方法,并且在模板方法被调用。

模板方法:可以有一个或几个,一般是一个具体方法,即一个框架,实现对基本方法的调度,完成固定的逻辑

注:为了防止被恶意操作,C++中可以使用两种方式

  • 模板方法为虚函数,但是需要加上 final 关键字,使之在子类中不被覆写。
  • 模板方法为非虚函数。

类图中的 ConcreteClass1 和 ConcreteClass2 属于具体模板,实现父类所定义的一个或多个抽象方法,也就是父类定义的基本方法在子类中得以实现。

(3)代码

注:抽象模板中的基本方法尽量设计为 protected 类型,符合迪米特法则,不需要暴露的属性或方法尽量不要设置为 protected 类型。实现类若非必要,尽量不要扩大父类中的访问权限。

#include <iostream>class AbstractClass
{
protected:virtual void doSomething() = 0; //基本方法virtual void doAngthing() = 0;public:virtual void templateMethod() final //模板方法{this->doSomething();this->doAngthing();}
};class ConcreteClass1 : public AbstractClass
{
protected:virtual void doSomething() { std::cout << "ConcreteClass1 : doSomething" << std::endl; }virtual void doAngthing() { std::cout << "ConcreteClass1 : doAngthing" << std::endl; }
};class ConcreteClass2 : public AbstractClass
{
protected:virtual void doSomething() { std::cout << "ConcreteClass2 : doSomething" << std::endl; }virtual void doAngthing() { std::cout << "ConcreteClass2 : doAngthing" << std::endl; }
};int main()
{AbstractClass *class1 = new ConcreteClass1();AbstractClass *class2 = new ConcreteClass2();class1->templateMethod();class2->templateMethod();delete class1;delete class2;return 0;
}

2、汽车模型

(1)UML图

(2)UML说明

悍马车有两个型号,H1 和 H2。按需求,只需要给出悍马车模型。此处有一个抽象类,然后两个不同型号的模型实现类,通过简单继承就可以实现业务需求。

(3)结构说明

HummerModel 抽象类,在类中定义了发动、停止、鸣笛、引擎、跑几个方法。根据不同型号来进行不同的实现。

(4)代码

#include <iostream>class HummerModel
{
protected:virtual void start() = 0;virtual void stop() = 0;virtual void alarm() = 0;virtual void enginBoom() = 0;public:void run(){this->start();this->enginBoom();this->alarm();this->stop();}
};class HummerH1Model : public HummerModel
{
protected:virtual void start() { std::cout << "HummerH1 : start" << std::endl; }virtual void stop(){std::cout << "HummerH1 : stop" << std::endl;}virtual void alarm(){std::cout << "HummerH1 : alarm" << std::endl;}virtual void enginBoom(){std::cout << "HummerH1 : enginBoom" << std::endl;}
};class HummerH2Model : public HummerModel
{
protected:virtual void start(){std::cout << "HummerH2 : start" << std::endl;}virtual void stop(){std::cout << "HummerH2 : stop" << std::endl;}virtual void alarm(){std::cout << "HummerH2 : alarm" << std::endl;}virtual void enginBoom(){std::cout << "HummerH2 : enginBoom" << std::endl;}
};int main()
{HummerModel *h1 = new HummerH1Model();HummerModel *h2 = new HummerH2Model();h1->run();h2->run();return 0;
}

三、模板方法模式的应用

1、优点

  • 封装不变部分,扩展可变部分。例如,汽车模型中,增加一个H3型号的模型,增加一个子类,实现父类的基本方法就可以。
  • 提取公共部分代码,便于维护。
  • 行为由父类控制,子类实现。

2、使用场景

  • 多个子类有共有的方法,并且逻辑基本相同时。
  • 重要、复杂的算法,可以把核心算法设计为模板方法,周边相关细节功能由各个子类实现。
  • 重构时,把相同代码抽取到父类中,通过钩子函数(见“模板方法模式的扩展”)约束其行为。

四、模板方法模式的扩展

1、汽车模型

增加需求 H1的喇叭是否响可控,H2的喇叭不响。

(1)UML图

(2)UML说明

在抽象类 HummerModel 中增加了一个实现方法 isAlarm,确定各个型号的车是否需要声音,由各个实现类覆写该方法,同时其他基本方法由于不需要对外提供访问,因此也设计为 protected 类型。

(3)代码

#include <iostream>class HummerModel
{
protected:virtual void start() = 0;virtual void stop() = 0;virtual void alarm() = 0;virtual void enginBoom() = 0;virtual bool isAlarm() { return true; }public:void run(){this->start();this->enginBoom();if (this->isAlarm()){this->alarm();}this->stop();}
};class HummerH1Model : public HummerModel
{
public:void setAlarm(bool OK) { this->m_alarmFlag = OK; }protected:virtual void start() { std::cout << "HummerH1 : start" << std::endl; }virtual void stop() { std::cout << "HummerH1 : stop" << std::endl; }virtual void alarm() { std::cout << "HummerH1 : alarm" << std::endl; }virtual void enginBoom() { std::cout << "HummerH1 : enginBoom" << std::endl; }virtual bool isAlarm() { return this->m_alarmFlag; }private:bool m_alarmFlag;
};class HummerH2Model : public HummerModel
{
protected:virtual void start() { std::cout << "HummerH2 : start" << std::endl; }virtual void stop() { std::cout << "HummerH2 : stop" << std::endl; }virtual void alarm() { std::cout << "HummerH2 : alarm" << std::endl; }virtual void enginBoom() { std::cout << "HummerH2 : enginBoom" << std::endl; }virtual bool isAlarm() { return false; }
};int main()
{HummerH1Model h1;HummerH2Model h2;h1.setAlarm(true);h1.run();h2.run();return 0;
}

五、最佳实践

1、合适的方法

父类建立框架,子类重写了父类部分方法后,再调用从父类继承的方法,产生不同的结果,即模板方式。

2、开源框架中的使用

开源框架提供了一个抽象类,然后有一堆子类,如果需要扩展功能,可以继承这个抽象类,然后覆写 protected 方法,然后调用一个类似 execute方法,即可扩展。

(完)

C/Cpp / 设计模式 / 模板模式相关推荐

  1. 12. 星际争霸之php设计模式--模板模式

    题记 ============================================================================== 本php设计模式专辑来源于博客(jy ...

  2. Java设计模式-模板模式

    Java设计模式-模板模式 什么是模板模式? 模板模式,顾名思义,就是通过模板拓印的方式. 定义模板,就是定义框架.结构.原型.定义一个我们共同遵守的约定. 定义模板,我们的剩余工作就是对其进行充实. ...

  3. Java设计模式—模板模式(Template)

    模板模式 业务需求 编写豆浆制作程序 选材-添加配料-浸泡-豆浆机打碎 选材.浸泡.打碎这几步对于制作不同豆浆都是一样的 比较简单,这里不再使用传统方法,直接上设计模式 模板模式基本介绍 模板模式,在 ...

  4. 【设计模式】Java设计模式 - 模板模式

    [设计模式]Java设计模式 - 模板模式

  5. C语言实现设计模式—模板模式

    文章目录 C语言实现设计模式-模板模式 模板模式介绍 UML用例说明 实际场景使用 框架结构[共用框架]-通用的串口协议分析函数 不同实现-数据类型区别 C语言实现设计模式-模板模式 模板模式介绍 在 ...

  6. 16、Python与设计模式--模板模式

    一.股票查询客户端 投资股票是种常见的理财方式,我国股民越来越多,实时查询股票的需求也越来越大.今天,我们通过一个简单的股票查询客户端来认识一种简单的设计模式:模板模式. 根据股票代码来查询股价分为如 ...

  7. PHP设计模式——模板模式

    声明:本系列博客参考资料<大话设计模式>,作者程杰. 模板模式准备一个抽象类,将部分逻辑以具体方法以及具体构造形式实现,然后声明一些抽象方法来迫使子类实现剩余的逻辑.不同的子类可以以不同的 ...

  8. 设计模式 模板模式和策略模式

    模板模式和策略模式,有相识的地方,都是通过对钩子方法的调用,来实现一个业务的完整逻辑. 所以这里我将两种模式放在一起介绍,比较容易加深对这两种模式的理解. 模板模式 在模板模式(Template Pa ...

  9. java设计模式————模板模式,手撸一个JDBCTemplate

    模板模式(Template Method Pattern) 定义一个算法的骨架,并允许子类为一个或者多个步骤提供实现. 模板方法使得子类可以在不改变算法结构的情况下,重新定义算法的某些步骤. 属于行为 ...

最新文章

  1. 深度学习中的线代基础
  2. 用 openssl 生成 SSL 使用的私钥和证书,并自己做 CA 签名
  3. 【python数据挖掘课程】十六.逻辑回归LogisticRegression分析鸢尾花数据
  4. CodeForces - 123A prime permutation(并查集,水题)
  5. css3蒙版运动,纯CSS3制作逼真的汽车运动动画
  6. PHP面向对象 封装与继承
  7. XState Viz 可视化和调试状态机
  8. 架构语言ArchiMate -应用层(Application Layer)
  9. 为什么在idea没有preview_设计学研究的idea从哪里来?
  10. jdk TreeMap源码解析
  11. 19.4.17 javaScript基础 培训第三天
  12. cad隐藏图层命令快捷键_CAD各种插件大全汇总,1G多绘图神器+快捷键命令大全,无套路分享...
  13. live555作为RTSP客户端对接大华的某款球机RTSP流时不能预览问题的解决方案
  14. Oracle 设置数据库时区
  15. delphi 各版本的特性
  16. 利用JavaScript实现不同时间 显示不同问候语
  17. tooth的用法_tooth的复数形式
  18. 人脸识别App面临的安全风险
  19. TCP三次握手四次挥手简介
  20. SAS_9.3_64位_安装方法(验证可用)

热门文章

  1. 阿里云主机安装Memcached扩展优化WordPress
  2. 从物理到虚拟一次真实的迁移
  3. 用 jQuery 获取 iframe 父子页面元素
  4. MapInfo之格式说明(转载)
  5. Mysql动态数据多条件查询
  6. 【收藏】如何避免everything每次都重建索引
  7. Linux centos7 配置用户自动登录
  8. docker 每次都得source /etc/profile以及如何查看Docker容器环境变量、向容器传递环境变量
  9. 【网址收藏】rancher镜像源仓库
  10. jQuery EasyUI 选项卡面板tabs使用实例精讲