介绍说明

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

举例说明

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

  1. class FirmwareUpgrade
  2. {
  3. protected:
  4. // 具体的串口操作实现延迟到子类实现
  5. // 在不同的平台下, 提供对应平台的串口操作实现即可
  6. virtual bool openSerialPort(int nBaudRate, int nDataBit, int nStopBit, int nParityBit) = 0;
  7. virtual bool wrtieSerialPort(void *pOutBuffer, size_t nLength) = 0;
  8. virtual size_t readSerialPort(void *pInBuffer, size_t size) = 0;
  9. virtual bool closeSerialPort() = 0;
  10. public:
  11. FirmwareUpgrade() {};
  12. virtual ~FirmwareUpgrade() {};
  13. // 开始升级
  14. bool upgrade(const char *pFirmwareFile) {
  15. init();
  16. ...
  17. enterUpgradeMode();
  18. ...
  19. erasePartition();
  20. ...
  21. updatePartition(pFirmwareFile);
  22. ...
  23. verifyPartition();
  24. ...
  25. resetDevice();
  26. ...
  27. release();
  28. return true;
  29. }
  30. private:
  31. bool sendCommand(int cmd, void *pdata, size_t size) {
  32. if (!wrtieSerialPort(package, sizeof(package))) {
  33. return false;
  34. }
  35. if(readSerialPort(package, sizeof(package))) {
  36. return false;
  37. }
  38. return package->done;
  39. }
  40. bool init(){
  41. ...
  42. if (!openSerialPort(115200, 8, 1, 0)) {
  43. return false;
  44. }
  45. ...
  46. return true;
  47. }
  48. bool enterUpgradeMode(){
  49. ...
  50. }
  51. bool erasePartition(){
  52. ...
  53. }
  54. bool updatePartition(const char *pFirmwareFile){
  55. FILE fp = fopen(pFirmwareFilel, "rb");
  56. ...
  57. while (fread(buffer, sizeof(buffer), 1, fp) == 1)
  58. {
  59. if (!sendCommand(update_COMMAND, NULL, 0)) {
  60. fclose(fp);
  61. return false;
  62. }
  63. }
  64. ...
  65. fclose(fp);
  66. return true;
  67. }
  68. bool verifyPartition() {
  69. ...
  70. }
  71. bool resetDevice(){
  72. ...
  73. }
  74. bool release() {
  75. ...
  76. return closeSerialPort();
  77. }
  78. };

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


  1. class FirmwareUpgradeWin : public FirmwareUpgrade
  2. {
  3. private:
  4. virtual bool openSerialPort(int nBaudRate, int nDataBit, int nStopBit, int nParityBit)
  5. {
  6. com_handle = CreateFile("//.//COM9", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  7. if (com_handle != INVALID_HANDLE_VALUE){
  8. ...
  9. }
  10. ...
  11. }
  12. virtual bool wrtieSerialPort(void *pOutBuffer, size_t nLength)
  13. {
  14. if (com_handle != INVALID_HANDLE_VALUE)
  15. {
  16. DWORD NumberOfBytesWrite;
  17. if (!WriteFile(com_handle, buffer, length, &NumberOfBytesWrite, NULL))
  18. {
  19. DWORD error = GetLastError();
  20. printf("error:%d\n", error);
  21. }
  22. return NumberOfBytesWrite;
  23. }
  24. }
  25. virtual size_t readSerialPort(void *pInBuffer, size_t size)
  26. {
  27. if (com_handle != INVALID_HANDLE_VALUE)
  28. {
  29. DWORD NumberOfBytesRead;
  30. ReadFile(com_handle, buffer, length, &NumberOfBytesRead, NULL);
  31. return NumberOfBytesRead;
  32. }
  33. return 0;
  34. }
  35. virtual bool closeSerialPort()
  36. {
  37. // 关闭硬件接口
  38. if (com_handle != INVALID_HANDLE_VALUE)
  39. {
  40. CloseHandle(com_handle);
  41. }
  42. }
  43. public
  44. bool upgrade(const char *pFirmwareFile) {
  45. return FirmwareUpgrade::upgrade(pFirmwareFile);
  46. }
  47. };
  48. int main()
  49. {
  50. FirmwareUpgradeWin mFirmwareUpgrade;
  51. mFirmwareUpgrade.upgrade("d:\\xxxx.bin");
  52. return 0;
  53. }

如 Linux 平台下的实现:

  1. class FirmwareUpgradeLinux : public FirmwareUpgrade
  2. {
  3. private:
  4. virtual bool openSerialPort(int nBaudRate, int nDataBit, int nStopBit, int nParityBit)
  5. {
  6. m_fd = ::open(device_node, O_RDWR | O_NOCTTY);
  7. ....
  8. tcgetattr(m_fd, &m_options);
  9. ....
  10. return true;
  11. }
  12. virtual bool wrtieSerialPort(void *pOutBuffer, size_t nLength)
  13. {
  14. ...
  15. byte = write(m_fd, pOutBuffer, nLength));
  16. ...
  17. return true;
  18. }
  19. virtual size_t readSerialPort(void *pInBuffer, size_t size)
  20. {
  21. ...
  22. select(m_fd + 1, &fs_read, NULL, NULL, &time);
  23. ...
  24. byte = read(m_fd, data, size);
  25. ...
  26. return byte;
  27. }
  28. virtual bool closeSerialPort()
  29. {
  30. ...
  31. close(m_fd);
  32. ...
  33. return true
  34. }
  35. public:
  36. bool upgrade(const char *pFirmwareFile) {
  37. return FirmwareUpgrade::upgrade(pFirmwareFile);
  38. }
  39. };
  40. int main()
  41. {
  42. FirmwareUpgradeLinux mFirmwareUpgrade;
  43. mFirmwareUpgrade.upgrade("d:\\xxxx.bin");
  44. return 0;
  45. }

总结说明

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

【学习笔记】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. vue 使用vuex 刷新时保存数据

    created () { this.$store.replaceState(Object.assign(this.$store.state,JSON.parse(localStorage.getIte ...

  2. Vue3 企业级优雅实战 - 组件库框架 - 6 搭建example环境

    该系列已更新文章: 分享一个实用的 vite + vue3 组件库脚手架工具,提升开发效率 开箱即用 yyg-cli 脚手架:快速创建 vue3 组件库和vue3 全家桶项目 Vue3 企业级优雅实战 ...

  3. 动态规划篇——DP问题

    动态规划篇--DP问题 本次我们介绍动态规划篇的DP问题,我们会从下面几个角度来介绍: 区间DP 计数DP 树状DP 记忆化搜索 区间DP 我们通过一个案例来讲解区间DP: /*题目展示*/ 题目名: ...

  4. C++使用ODBC连接数据库遇到的问题

    C++使用ODBC连接数据库遇到的问题 1.SQL语句中包含中文无法正常执行的问题 2.字符与宽字符相互转化的问题 C++使用ODBC连接数据库遇到的问题 1.SQL语句中包含中文无法正常执行的问题 ...

  5. 使用Typora

    Markdown学习 标题:#+空格+名称 二级标题 二级标题:##+空格+名称 三级标题 几级标题以此类推,最多支持到六级标题 字体 Hello,world! 变粗体:一句话的前后加上两个** 变斜 ...

  6. Keras网络可视化方法

    Keras网络可视化方法 Keras模型可视化 Keras可视化依赖的两个包 参考链接 Keras模型可视化 代码: from keras.utils import plot_model plot_m ...

  7. 一篇文章教你实战Docker容器数据卷

    在上一篇中,咱们对Docker中的容器数据卷做了介绍.已经知道了容器数据卷是什么?能干什么用.那么本篇咱们就来实战容器数据卷,Docker容器数据卷案例主要做以下三个案例 1:宿主机(也就是Docke ...

  8. f-strings: Python字符串处理的瑞士军刀

    从 3.6 开始,Python 新增了一个格式化字符串的方法,称之为 f-string. 其用法就是在python原始字符串的基础上增加 f/F 前缀,以大括号 {} 标明被替换的字段. f-stri ...

  9. python中使用pip 安装第三方库报错归类及解决方式

    1.  离线安装virtualenv报错,安装命令:python setup.py install 解决方式:升级setuptools 2.  安装第三方库时安装失败,安装命令:pip install ...

  10. 第三章 --------------------XAML的属性和事件

    1.XAML注释是什么样子的? 在之前的章节有提起过,但是这一节我还是想系统的学习XAML,XAML的注释如下 <!-- //这其中填写注释 --> Notice:在注释的部分编译器是不编 ...