设计模式学习[9]---模板方法模式

devtools/2024/11/28 3:44:36/

文章目录

  • 前言
    • 1.原理阐述
    • 2.举例
    • 3.和原型模式的区别
  • 总结

前言

大型的C++项目,都会用到很多模板,C++中关于模板的书也不少,那么在设计模式中的模板模式和C++的模板又有什么区别呢?模板和上篇的原型又有哪些不同?

这篇博客就详细介绍一下。

1.原理阐述

1.1 C++模板说明

在C++中,模板称之为 t e m p l a t e template template。一般把一系列相同定义、相同业务逻辑但类型不同等情况的函数提取出来,作为一个模板,其中共性的部分作为模板。

比如一个比较函数,有int类型的比较函数和float类型的比较函数,如果A比B大则返回1,否则返回-1
下面是一个不严谨的例子,简单看看

template<typename T>
int m_funCompare(const T &A,const T &B)
{if(A>B)return 1;if(A<B)return -1;return 0;
}

这里我们把比较的过程抽离出来,业务逻辑都是一致的,只是比较的参数不同,所以用模板无疑节省了不少工作量。

1.2 设计模式模板

对于模板方法模式,和C++的模板有点类似,但又不完全相同。
书中的定义如下:

模板方法模式定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。

讲下个人理解:
就是业务流程基本一致,但是在面向对象开发的时候,不同子类的对象对于父类对象的某个操作,有不同的实现方式。其实就是多态的一种体现。

比如我们说鸟会鸣叫,那么麻雀和布谷鸟的鸣叫肯定是不一样的,但是在面向对象开发的时候,我们统一是通过去调用“鸣叫”这个接口(当然如果你硬要用麻雀去调用鸣叫接口,我也没话说),那么我们能否认为这个调用过程其实是固定的,可以认为它就是一种模板。鸟这个父类下面的子类,针对这个接口做不同的实现,但是子类并没有改变这个调用的一个流程。

所以模板方法模式在实现上就是,用父类包装一层相对固定的流程/算法/业务,用子类继承,在子类上面做一些特定的操作。

2.举例

下面将鸟类的例子做一下简单的代码实现

#include<iostream>
using namespace std;
class Bird
{
public:void start(){cout<<"鸟叫开始"<<endl;}virtual void sing()=0;void end(){cout<<"鸟叫结束"<<endl;}void action(){start();sing();end();}
};
class sparrow : public Bird
{void sing(){cout<<""叽叽喳喳"<<endl;}
};
class cuckoo: public Bird
{void sing(){cout<<""布谷布谷"<<endl;}
};
int main()
{Bird* bird1=new sparrow();Bird* bird2=new cuckoo();bird1->action();bird2->action();
}

上面的程序打印内容如下:

鸟叫开始
叽叽喳喳
鸟叫结束
鸟叫开始
布谷布谷
鸟叫结束

这个例子中我把共性的业务流程/算法,放到父类Bird中,不同的子类(鸟),重新实现某个具体的步骤,这里是鸟叫。

3.和原型模式的区别

原型模式
原型模式更倾向于是对象创建,它属于创建型的设计模式。重点是在于对象的创建初始化。
而模板类型,是提取共有的一些过程,它的重点在于过程。模板方法模式它实际上是属于行为型模式。
两者在名字上听起来有点类似,模板,原型,原型不就是类似于一个模板,模板不就是一个原型吗。但是具体的运用场景还是不太一样的,这里要注意。

总结

我们在开发的时候遇到一些共性的业务流程,如果一味的用最简单的逻辑去做,往往是代码量大了,但是重复,冗余。
代码质量很低,同时显得自己的水平也不高。模板方法模式是一种代码复用技术,遇到这种大量重复冗余的情况,多想想设计模式,用多态的思想去处理问题,代码水平更上一层楼。


http://www.ppmy.cn/devtools/137559.html

相关文章

Python后端flask框架接收zip压缩包方法

一、用base64编码发送&#xff0c;以及接收 import base64 import io import zipfile from flask import request, jsonifydef unzip_and_find_png(zip_data):# 使用 BytesIO 在内存中处理 zip 数据with zipfile.ZipFile(io.BytesIO(zip_data), r) as zip_ref:extracted_paths…

EasyAnimate:基于Transformer架构的高性能长视频生成方法

这里主要是对EasyAnimate的论文阅读记录&#xff0c;感兴趣的话可以参考一下&#xff0c;如果想要直接阅读原英文论文的话地址在这里&#xff0c;如下所示&#xff1a; 摘要 本文介绍了EasyAnimate&#xff0c;一种利用Transformer架构实现高性能视频生成的高级方法。我们将原…

centos 服务器 docker 使用代理

宿主机使用代理 在宿主机的全局配置文件中添加代理信息 vim /etc/profile export http_proxyhttp://127.0.0.1:7897 export https_proxyhttp://127.0.0.1:7897 export no_proxy"localhost,127.0.0.1,::1,172.171.0.0" docker 命令使用代理 例如我想在使用使用 do…

java基础概念38:正则表达式3-捕获分组

一、定义 分组就是一个小括号。 分组的特点&#xff1a; 二、捕获分组 捕获分组就是把这一组的数据捕获出来&#xff0c;再用一次。 后续还要继续使用本组的数据。 正则内部使用&#xff1a;\\组号正则外部使用&#xff1a;$组号 2-1、正则内部使用&#xff1a;\\组号 示…

开源生态发展合作倡议

在信息技术发展的浪潮中&#xff0c;开源已成为全球创新的强劲引擎&#xff0c;深刻影响着各行各业的发展。今天&#xff0c;我们站在新的历史起点上&#xff0c;肩负着推动开源生态发展的重任。在此&#xff0c;开源欧拉&#xff08;openEuler&#xff09;、龙蜥&#xff08;O…

【数据结构-队列】力扣232. 用栈实现队列

请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作&#xff08;push、pop、peek、empty&#xff09;&#xff1a; 实现 MyQueue 类&#xff1a; void push(int x) 将元素 x 推到队列的末尾 int pop() 从队列的开头移除并返回元素 int peek() 返回队列开头…

vueuse中的useTemplateRefsList

在 v-for 中绑定 ref 到模板元素和组件的简写方式 Demo1 <script setup lang"ts"> import { onUpdated } from vue import { useTemplateRefsList } from vueuse/coreconst refs useTemplateRefsList<HTMLDivElement>()onUpdated(() > {console.lo…

微信小程序常用全局配置项及窗口组成部分详解

微信小程序常用全局配置项及窗口组成部分详解 引言 微信小程序作为一种新兴的应用形态,凭借其轻量级、便捷性和丰富的功能,已成为开发者和用户的热门选择。在开发小程序的过程中,了解全局配置项和窗口组成部分是至关重要的。本文将详细介绍微信小程序的常用全局配置项及窗…