设计模式 19 模板模式 Template Pattern

news2024/11/18 15:44:07
设计模式 19 模板模式 Template Pattern

1.定义

        模板模式(Template Pattern)是一种行为设计模式,它定义了一个算法的骨架,将一些步骤的具体实现延迟到子类中。在模板模式中,定义了一个抽象类,其中包含了一个模板方法(template method),这个方法定义了算法的基本结构和步骤,但其中的具体步骤由子类来实现。

        模板模式主要用于在不同子类中封装通用的行为,同时保持整体算法结构的一致性。通过模板方法模式,使得父类能够控制方法的执行顺序,同时细节延迟到子类实现。

2.内涵

模板模式包含以下几个角色:

  1. Abstract Class(抽象类):定义了一个模板方法,该方法是算法的骨架,其中调用了一系列抽象或具体的步骤。抽象类可能还包含了一些通用的实现,这些实现可以在模板方法中直接调用,也可以在需要时在子类中覆盖。
  2. Concrete Class(具体类):继承自抽象类,并实现了其中的具体步骤。每个具体类可以根据需要实现抽象类中定义的方法,并将其组合在一起形成完整的算法。

通过模板模式,可以实现代码复用、减少重复代码的编写,同时保持算法的统一性和一致性。模板模式能够提供一个稳定的算法框架,同时允许子类自由扩展或修改算法的某些部分。

=======================
|      AbstractClass   |
|----------------------|
|+ templateMethod()   |  
|+ primitiveOperation1()|
|+ primitiveOperation2()|
=======================
             |
             |
             |
             |
      =====================
      |    ConcreteClassA   |
      |----------------------|
      |# primitiveOperation1()|
      |# primitiveOperation2()|
      =====================
             |
             |
             |
             |
     =====================
     |   ConcreteClassB    |
     |----------------------|
     |# primitiveOperation1()|
     |# primitiveOperation2()|
     =====================


     
AbstractClass(抽象类):这是模板模式的核心部分,抽象类定义了模板方法 templateMethod() 和两个抽象方法 primitiveOperation1() 和 primitiveOperation2(),其中 templateMethod() 指定了算法的框架,包括一系列调用步骤,而 primitiveOperation1() 和 primitiveOperation2() 则是需要在具体子类中实现的具体步骤。

ConcreteClassA 和 ConcreteClassB(具体类):这是实际实现模板模式的具体子类。它们继承了 AbstractClass 并实现了其中的抽象方法 primitiveOperation1() 和 primitiveOperation2()。每个具体类可能实现完全不同的具体步骤,但是它们遵循相同的模板方法结构(templateMethod())。

     
     
3.使用示例

/**
 * The Abstract Class defines a template method 
 */
class AbstractClass {
  /**
   * The template method defines the skeleton of an algorithm.
   */
 public:
  void TemplateMethod() const {
    this->BaseOperation1();
    this->RequiredOperations1();
    this->BaseOperation2();
    this->Hook1();
    this->RequiredOperation2();
    this->BaseOperation3();
    this->Hook2();
  }

 protected:
  void BaseOperation1() const {
    std::cout << "AbstractClass says: I am doing the bulk of the work\n";
  }
  void BaseOperation2() const {
    std::cout << "AbstractClass says: But I let subclasses override some operations\n";
  }
  void BaseOperation3() const {
    std::cout << "AbstractClass says: But I am doing the bulk of the work anyway\n";
  }
  
  
  virtual void RequiredOperations1() const = 0;
  virtual void RequiredOperation2() const = 0;
  
  
  virtual void Hook1() const {}
  virtual void Hook2() const {}
};


/**
 * Concrete classes have to implement all abstract operations of the base class.
 * They can also override some operations with a default implementation.
 */
class ConcreteClass1 : public AbstractClass {
 protected:
  void RequiredOperations1() const override {
    std::cout << "ConcreteClass1 says: Implemented Operation1\n";
  }
  void RequiredOperation2() const override {
    std::cout << "ConcreteClass1 says: Implemented Operation2\n";
  }
};


class ConcreteClass2 : public AbstractClass {
 protected:
  void RequiredOperations1() const override {
    std::cout << "ConcreteClass2 says: Implemented Operation1\n";
  }
  void RequiredOperation2() const override {
    std::cout << "ConcreteClass2 says: Implemented Operation2\n";
  }
  void Hook1() const override {
    std::cout << "ConcreteClass2 says: Overridden Hook1\n";
  }
};

void ClientCode(AbstractClass *class_) {
  // ...
  class_->TemplateMethod();
  // ...
}

int main() {
  std::cout << "Same client code can work with different subclasses:\n";
  ConcreteClass1 *concreteClass1 = new ConcreteClass1;
  ClientCode(concreteClass1);
  std::cout << "\n";
  std::cout << "Same client code can work with different subclasses:\n";
  ConcreteClass2 *concreteClass2 = new ConcreteClass2;
  ClientCode(concreteClass2);
  delete concreteClass1;
  delete concreteClass2;
  return 0;
}


输出:

Same client code can work with different subclasses:
AbstractClass says: I am doing the bulk of the work
ConcreteClass1 says: Implemented Operation1
AbstractClass says: But I let subclasses override some operations
ConcreteClass1 says: Implemented Operation2
AbstractClass says: But I am doing the bulk of the work anyway

Same client code can work with different subclasses:
AbstractClass says: I am doing the bulk of the work
ConcreteClass2 says: Implemented Operation1
AbstractClass says: But I let subclasses override some operations
ConcreteClass2 says: Overridden Hook1
ConcreteClass2 says: Implemented Operation2
AbstractClass says: But I am doing the bulk of the work anyway

上述代码类图


4.注意事项

在使用模板模式(Template Pattern)时,有一些注意事项需要注意以避免可能的问题和踩坑:

  • 抽象类的设计:在定义抽象类时,需要仔细考虑模板方法中的逻辑和步骤顺序,确保所有子类都能正确实现这些步骤。避免在抽象类中定义过多的具体实现,应保持抽象类的简洁性,只包含框架结构和必要的抽象方法。
  • 子类实现的一致性:子类在实现抽象方法时,需要保持接口一致性,确保方法签名和返回类型与父类中定义的一致。否则可能会导致编译错误或运行时异常。
  • 算法的扩展性:模板模式允许子类修改或扩展算法的某些部分,但注意避免过度扩展和修改,以免破坏算法的一致性和规范性。确保扩展的功能是相对独立且有必要的。
  • 模板方法的执行顺序:模板方法定义了算法的执行顺序,子类在实现具体步骤时要遵循这个顺序。任何不当的调整可能会导致算法步骤的混乱或错误。
  • 继承的关系:模板模式使用了继承机制,但应该避免过度使用继承导致类层次结构复杂。确保继承关系的合适性和合理性。
  • 钩子方法:在抽象类中可以定义钩子方法,用于控制算法的某些部分是否执行。需要谨慎设计和使用钩子方法,避免影响算法的整体结构和正确性。
  • 单一职责原则:确保每个具体类只负责实现自己的具体步骤,遵循单一职责原则,避免一个类承担过多的责任和功能。
5.最佳实践


在开发中实现模板模式(Template Pattern)时,可以采用以下一些比较好的经验:

  • 合理抽象和分离关注点:在设计抽象类时,需要将通用的算法步骤抽象出来,同时将具体步骤留给具体子类实现。这样可以实现算法的复用和解耦,同时方便后续的扩展和修改。
  • 使用钩子方法:钩子方法是一种可以控制算法流程的手段,可以在抽象类中定义一些空方法或默认实现,具体子类可以选择性地重写这些方法来影响算法的执行。这样可以在不改变模板方法结构的情况下灵活地扩展和定制算法。
  • 保持一致性:确保所有具体子类实现的具体步骤都是与抽象类中定义的一致的,保持算法的一致性和规范性,避免出现错误或混乱。
  • 封装变化部分:在设计模板模式时,将会变化的部分抽象出来,以便随时扩展和修改,而将不变的部分固定在模板方法中,确保算法的稳定性和可维护性。
  • 使用工厂方法:在具体类的实例化时,可以考虑使用工厂方法模式(Factory Method Pattern),将实例化过程放在具体的工厂类中,以便灵活地切换不同的具体子类。

6.总结

通过模板模式,可以实现代码复用、减少重复代码的编写,同时保持算法的统一性和一致性。模板模式能够提供一个稳定的算法框架,同时允许子类自由扩展或修改算法的某些部分。


 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1704317.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2024.5组队学习——MetaGPT(0.8.1)智能体理论与实战(中):订阅智能体OSS实现

传送门&#xff1a; 《2024.5组队学习——MetaGPT&#xff08;0.8.1&#xff09;智能体理论与实战&#xff08;上&#xff09;&#xff1a;MetaGPT安装、单智能体开发》《2024.5组队学习——MetaGPT&#xff08;0.8.1&#xff09;智能体理论与实战&#xff08;下&#xff09;&…

2024年电工杯高校数学建模竞赛(A题) 建模解析| 园区微电网风光储协调优化配置

问题重述及方法概述 问题1&#xff1a;各园区独立运营储能配置方案及其经济性分析 经济性分析采用成本-效益分析方法&#xff0c;计算购电量、弃风弃光电量、总供电成本和单位电量平均供电成本等指标。 问题2&#xff1a;联合园区储能配置方案及其经济性分析 经济性分析采用成…

《Ai企业知识库》-rasa X安装使用

背景&#xff1a; Rasa X 是一个为构建、改进和管理对话式AI助手而设计的工具。它是Rasa开源机器学习框架的一个扩展&#xff0c;旨在实现“对话驱动开发”&#xff08;Conversation-Driven Development&#xff09;。Rasa X 主要特点包括&#xff1a; 交互式学习&#xff1a;…

百度智能小程序源码系统 关键词推广优化排名高 带完整的安装代码包以及搭建教程

系统概述 百度智能小程序源码系统是一套完整的解决方案&#xff0c;为用户提供了创建、发布和管理智能小程序的平台。它基于百度平台的先进技术&#xff0c;确保小程序在运行和展示方面具有出色的表现。 代码示例 系统特色功能 1.关键词推广优化&#xff1a;系统内置了强大的…

Day 40 Web容器-Tomcat

Tomcat 一&#xff1a;Tomcat简介 1.简介 ​ Tomcat是Apache软件基金会&#xff08;Apache Software Foundation&#xff09;的Jakarta 项目中的一个核心项目 ​ Tomcat服务器是一个免费的开放源代码的Web应用服务器&#xff0c;属于轻量级应用服务器 ​ Tomcat是WEB容器/WE…

JVM(内存区域划分、类加载机制、垃圾回收机制)

目录 一. 内存区域划分 1.本地方法栈(Native Method Stacks) 2.虚拟机栈(JVM Stacks) 3.程序计数器(Program Counter Register) 4.堆(Heap) 5.元数据区(Metaspace) 二.类加载机制 1.加载 2.验证 3.准备 4.解析 5.初始化 "双亲委派模型" 三. GC 垃圾回收…

[自动驾驶技术]-7 Tesla自动驾驶方案之算法(AI Day 2022)

特斯拉在2022年AI Day上更新了感知规控算法模型&#xff0c;核心引入了Occupancy技术。下图是特斯拉活动日展示的主题内容&#xff0c;本文主要解读Planning和Neural Network部分。 1 规划决策 Interaction search-交互搜索 特斯拉在自动驾驶规划中使用了一种高度复杂和优化的…

SpringCloud整合Seata1.5.2

Windows下部署Seata1.5.2可参照博文&#xff1a;Windows下部署Seata1.5.2&#xff0c;解决Seata无法启动问题-CSDN博客 1. 引入依赖 <!-- 分布式事务 --> <dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-st…

echarts配置记录,一些已经废弃的写法

1、normal&#xff0c;4.0以后无需将样式写在normal中了 改前&#xff1a; 改后&#xff1a; DEPRECATED: normal hierarchy in labelLine has been removed since 4.0. All style properties are configured in labelLine directly now. 2、axisLabel中的文字样式无需使用te…

近五年营收和净利润大幅“败北”,尚品宅配今年押注扩张加盟

​ 《港湾商业观察》廖紫雯 两个月前经历过高管公开信的尚品宅配&#xff08;300616.SZ&#xff09;&#xff0c;无论是2023年年报&#xff0c;还是今年一季报&#xff0c;虽然公司净利润表现尚佳&#xff0c;但收入端的持续承压仍然备受关注。 今年一季报&#xff0c;尚品宅…

Mac免费软件推荐

1. iTerm2 - 功能强大的终端 iTerm2 是一个功能强大且灵活的终端仿真器&#xff08;可替代系统默认终端&#xff09;&#xff0c;适合需要在 macOS 上进行大量终端操作的用户。其丰富的功能和高可定制性使得 iTerm2 成为许多开发者和系统管理员的首选工具。无论是处理多个会话…

RabbitMQ 之 死信队列

目录 ​编辑一、死信的概念 二、死信的来源 三、死信实战 1、代码架构图 2、消息 TTL 过期 &#xff08;1&#xff09;消费者 &#xff08;2&#xff09;生产者 &#xff08;3&#xff09;结果展示​编辑 3、队列达到最大长度 &#xff08;1&#xff09;消费者 &…

百度发布代码辅助工具,超强

不会用AI的程序员&#xff0c;会跟不会用智能手机的人一样 百度这个代码助手助手感觉还是不错的 https://comate.baidu.com/?inviteCodeijmce7dj 目前看下来这个代码助手是比较强的&#xff0c;比阿里的那个灵码好用&#xff0c;他可以引用到当前的文件&#xff0c;并且能分…

Spring Cache基本使用

Spring 从 3.1 版本开始定义缓存抽象来统一不同的缓存技术&#xff1b;在应用层面与后端存储之间&#xff0c;提供了一层抽象&#xff0c;这层抽象目的在于封装各种可插拔的后端存储( ehcache, redis, guava)&#xff0c;最小化因为缓存给现有业务代码带来的侵入。 一、Spring…

DRKCT复现

Osint 羡慕群友每一天 MISC 签到 扫码关注公众号&#xff0c;回复一下行 &#xff08;眼神要好&#xff0c; 我做题时没看见有个二维码&#xff09; 神秘的文字 把代码js运行一下 (用js的原因是前面给的动物代表的字符类似jsfuck代码) &#x13142;![]; &#x13080;!…

Daisy Chain

菊花链是双向和半双工的&#xff0c;因此在 COMH 和 COML 接口上有一个发送器 (TX) 和一个接收器 (RX)。TX 和 RX 功能由硬件根据器件的基底/堆栈检测自动控制。当接收到 WAKE ping/音调时&#xff0c;通信方向由 CONTROL1[DIR_SEL] 和 COMM_CTRL[TOP_STACK] 配置进行设置。 对…

如何处理网安发出的网络安全监督检查限期整改通知

近期&#xff0c;很多客户都收到了网安发出的限期整改通知。大家都比较关心的问题是&#xff0c;如何应对处理这些限期整改通知。后续是否有其他的影响&#xff0c;需要如何做进一步的优化整改和调整。今天就这些问题给大家做一些分享。 一. 为什么会有网安的网络安全检查 主…

系统管理、磁盘分区

系统管理 业务层面&#xff1a;为了满足一定的需求所做的特定操作。 硬盘是什么&#xff0c;硬盘的作用&#xff1a; **硬盘&#xff1a;**计算机的存储设备&#xff0c;机械硬盘是由一个或者多个磁性的盘组成&#xff0c;可以在盘片上进行数据的读写。 连接方式&#xff1a…

谈谈BlueStore的BitmapAllocator

背景 BlueStore在ceph里面承担了数据在底层磁盘上的读写任务&#xff0c;那它的功能里自然就有一块是管理磁盘空间使用的。说白了&#xff0c;就是记录&管理磁盘里哪些空间已经使用了&#xff0c;哪些空间还没有被使用。 目前官方的ceph里使用BitmapAllocator来管理磁盘空…

冯喜运:5.27黄金短线看震荡,今日黄金原油走势分析

【黄金消息面分析】&#xff1a;黄金作为传统的避险资产&#xff0c;在经济不确定性中扮演着至关重要的角色。近期&#xff0c;国际黄金价格经历了显著的波动。从5月9日的低点2325.19美元/盎司反弹至2340美元/盎司以上&#xff0c;尽管金价曾一度触及2449.89美元/盎司的历史高点…