介绍说明

模板设计模式是一种非常简单的设计模式,其主要是利用了虚函数的特性实现。非常适合应用在一些算法、流程、业务逻辑是固定的形式,其中某些步骤的实现方式又无法确定下来的场景。

举例说明

以下为模拟某芯片基于串口通信的固件升级代码,可以提供一个 FirmwareUpgrade 的类用于使用者集成。考虑到跨平台,该类的串口操作接口声明为纯虚函数,由使用者自己根据所用平台实现,而不需要关注具体的升级细节。

class FirmwareUpgrade
{
protected: // 具体的串口操作实现延迟到子类实现
// 在不同的平台下, 提供对应平台的串口操作实现即可
virtual bool openSerialPort(int nBaudRate, int nDataBit, int nStopBit, int nParityBit) = 0;
virtual bool wrtieSerialPort(void *pOutBuffer, size_t nLength) = 0;
virtual size_t readSerialPort(void *pInBuffer, size_t size) = 0;
virtual bool closeSerialPort() = 0; public: FirmwareUpgrade() {};
virtual ~FirmwareUpgrade() {}; // 开始升级
bool upgrade(const char *pFirmwareFile) { init();
...
enterUpgradeMode();
...
erasePartition();
...
updatePartition(pFirmwareFile);
...
verifyPartition();
...
resetDevice();
...
release(); return true;
} private: bool sendCommand(int cmd, void *pdata, size_t size) { if (!wrtieSerialPort(package, sizeof(package))) {
return false;
} if(readSerialPort(package, sizeof(package))) {
return false;
} return package->done;
} bool init(){
...
if (!openSerialPort(115200, 8, 1, 0)) {
return false;
}
...
return true;
} bool enterUpgradeMode(){
...
} bool erasePartition(){
...
} bool updatePartition(const char *pFirmwareFile){
FILE fp = fopen(pFirmwareFilel, "rb");
...
while (fread(buffer, sizeof(buffer), 1, fp) == 1)
{
if (!sendCommand(update_COMMAND, NULL, 0)) {
fclose(fp);
return false;
}
}
...
fclose(fp);
return true;
} bool verifyPartition() {
...
} bool resetDevice(){
...
} bool release() {
...
return closeSerialPort();
}
};

如 Windows 平台开发者,只需要利用  Windows 平台下接口实现串口的打开、写入、读取、关闭四个接口即可:


class FirmwareUpgradeWin : public FirmwareUpgrade
{
private: virtual bool openSerialPort(int nBaudRate, int nDataBit, int nStopBit, int nParityBit)
{ com_handle = CreateFile("//.//COM9", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (com_handle != INVALID_HANDLE_VALUE){
...
}
...
} virtual bool wrtieSerialPort(void *pOutBuffer, size_t nLength)
{
if (com_handle != INVALID_HANDLE_VALUE)
{
DWORD NumberOfBytesWrite;
if (!WriteFile(com_handle, buffer, length, &NumberOfBytesWrite, NULL))
{
DWORD error = GetLastError();
printf("error:%d\n", error);
}
return NumberOfBytesWrite;
}
} virtual size_t readSerialPort(void *pInBuffer, size_t size)
{
if (com_handle != INVALID_HANDLE_VALUE)
{
DWORD NumberOfBytesRead;
ReadFile(com_handle, buffer, length, &NumberOfBytesRead, NULL);
return NumberOfBytesRead;
}
return 0;
} virtual bool closeSerialPort()
{
// 关闭硬件接口
if (com_handle != INVALID_HANDLE_VALUE)
{
CloseHandle(com_handle);
}
} public bool upgrade(const char *pFirmwareFile) {
return FirmwareUpgrade::upgrade(pFirmwareFile);
}
}; int main()
{
FirmwareUpgradeWin mFirmwareUpgrade; mFirmwareUpgrade.upgrade("d:\\xxxx.bin"); return 0;
}

如 Linux 平台下的实现:

class FirmwareUpgradeLinux : public FirmwareUpgrade
{
private: virtual bool openSerialPort(int nBaudRate, int nDataBit, int nStopBit, int nParityBit)
{ m_fd = ::open(device_node, O_RDWR | O_NOCTTY);
....
tcgetattr(m_fd, &m_options);
....
return true;
} virtual bool wrtieSerialPort(void *pOutBuffer, size_t nLength)
{
...
byte = write(m_fd, pOutBuffer, nLength));
...
return true;
} virtual size_t readSerialPort(void *pInBuffer, size_t size)
{
...
select(m_fd + 1, &fs_read, NULL, NULL, &time);
...
byte = read(m_fd, data, size);
...
return byte;
} virtual bool closeSerialPort()
{
...
close(m_fd);
...
return true
} public: bool upgrade(const char *pFirmwareFile) {
return FirmwareUpgrade::upgrade(pFirmwareFile);
}
}; int main()
{
FirmwareUpgradeLinux mFirmwareUpgrade; mFirmwareUpgrade.upgrade("d:\\xxxx.bin"); return 0;
}

总结说明

主要就是将差异化的抽离出来,延迟到子类实现,而固定的逻辑处理则由父类封装并提供接口。相当于定义一个模板,子类只要按照这个模板实现相应的接口,由父类反向调用子类所实现的接口,来完成具体的逻辑功能。这样使用者不需要关心具体的升级逻辑实现,只需要按照要求完成相应的接口,即可使用升级功能,从而降低复杂性,又提升了灵活性。

【学习笔记】C/C++ 设计模式 - 模板模式的更多相关文章

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

    Java设计模式 - 模板模式 不断学习才是王道 继续踏上学习之路,学之分享笔记 总有一天我也能像各位大佬一样 原创作品,更多关注我CSDN: 一个有梦有戏的人 准备将博客园.CSDN一起记录分享自己 ...

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

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

  3. Django 学习笔记(五)模板标签

    关于Django模板标签官方网址https://docs.djangoproject.com/en/1.11/ref/templates/builtins/ 1.IF标签 Hello World/vi ...

  4. Django 学习笔记(四)模板变量

    关于Django模板变量官方网址:https://docs.djangoproject.com/en/1.11/ref/templates/builtins/ 1.传入普通变量 在hello/Hell ...

  5. Django 学习笔记(三)模板导入

    本章内容是将一个html网页放进模板中,并运行服务器将其展现出来. 平台:windows平台下Liunx子系统 目前的目录: hello ├── manage.py ├── hello │ ├── _ ...

  6. 并发编程学习笔记(9)----AQS的共享模式源码分析及CountDownLatch使用及原理

    1. AQS共享模式 前面已经说过了AQS的原理及独享模式的源码分析,今天就来学习共享模式下的AQS的几个接口的源码. 首先还是从顶级接口acquireShared()方法入手: public fin ...

  7. Redis学习笔记八:集群模式

    作者:Grey 原文地址:Redis学习笔记八:集群模式 前面提到的Redis学习笔记七:主从复制和哨兵只能解决Redis的单点压力大和单点故障问题,接下来要讲的Redis Cluster模式,主要是 ...

  8. 再起航,我的学习笔记之JavaScript设计模式30(简单模板模式)

    简单模板模式 概念介绍 简单模板模式(Simple template): 通过格式化字符串拼凑出视图避免创建视图时大量节点操作,优化内存开销. 创建模板 在实际的业务中如果我们需要进行前后台交互,或多 ...

  9. 再起航,我的学习笔记之JavaScript设计模式09(原型模式)

    我的学习笔记是根据我的学习情况来定期更新的,预计2-3天更新一章,主要是给大家分享一下,我所学到的知识,如果有什么错误请在评论中指点出来,我一定虚心接受,那么废话不多说开始我们今天的学习分享吧! 我们 ...

  10. 再起航,我的学习笔记之JavaScript设计模式05(简单工程模式)

    我的学习笔记是根据我的学习情况来定期更新的,预计2-3天更新一章,主要是给大家分享一下,我所学到的知识,如果有什么错误请在评论中指点出来,我一定虚心接受,那么废话不多说开始我们今天的学习分享吧! 前几 ...

随机推荐

  1. I-图的分割(二分+并查集)

    图的分割 题目大意: 给你n个点,m条边的图,没有重环和自环,所有的点都联通 可以通过删除几条边使得整个图变成两个联通子图 求删除的边中最大边权的最小值 解题思路: 看到"最大边权的最小值& ...

  2. JS数据结构与算法-数组结构

    数组结构 几乎所有的编程语言都原生支持数组类型,因为数组是最简单的内存数据结构. 数组通常情况下用于存储一系列同一种数据类型的值. 但在JavaScript里,也可以在数组中保存不同类型的值. 但我们 ...

  3. Java安全之动态加载字节码

    Java字节码 简单说,Java字节码就是.class后缀的文件,里面存放Java虚拟机执行的指令. 由于Java是一门跨平台的编译型语言,所以可以适用于不同平台,不同CPU的计算机,开发者只需要将自 ...

  4. 5、有一行电文,译码规律为: a ——> z b——> y c ——> x. 即把第一个字母变成第26个字母, 第i个字母变成第(26-i+1)个字母, 非字母字符不变

    /* 有一行电文,译码规律为: a --> z b--> y c --> x. 即把第一个字母变成第26个字母, 第i个字母变成第(26-i+1)个字母, 非字母字符不变 */ #i ...

  5. TCN代码详解-Torch (误导纠正)

    TCN代码详解-Torch (误导纠正) 1. 绪论 TCN网络由Shaojie Bai, J. Zico Kolter, Vladlen Koltun 三人于2018提出.对于序列预测而言,通常考虑 ...

  6. 《回炉重造》——Lambda表达式

    前言 Lambda 表达式(Lambda Expression),相信大家对 Lambda 肯定是很熟悉的,毕竟我们数学上经常用到它,即 λ .不过,感觉数学中的 Lambda 和编程语言中的 Lam ...

  7. 漫谈计算机网络:应用层 ----- 从DNS域名解析到WWW万维网再到P2P应用

    2022-12-04 18:31:01 纪念一下博主的<漫谈计算机网络>连载博客 浏览量破500了! 今天更新完结篇! 面试答不上?计网很枯燥? 听说你学习 计网 每次记了都会忘? 不妨抽 ...

  8. 【极客时间】大数据概述及HDFS介绍

  9. 【每日一题】【DFS】2022年1月5日-543. 二叉树的直径

    给定一棵二叉树,你需要计算它的直径长度.一棵二叉树的直径长度是任意两个结点路径长度中的最大值.这条路径可能穿过也可能不穿过根结点. 答案: /** * Definition for a binary ...

  10. Vue3 企业级优雅实战 - 组件库框架 - 8 搭建组件库 cli

    前面的文章分享了组件库的开发.example.组件库文档,本文分享组件库 cli 开发. 1 为什么要开发组件库 cli 回顾一个新组件的完整开发步骤: 1 在 packages 目录下创建组件目录 ...