模板方法模式介绍

目录

一、模板方法模式介绍

1.1 模板方法模式的定义

1.2 模板方法模式的原理

1.2.1 模板方法模式类图

1.2.2 类图角色说明

1.2.3 示例代码

二、模板方法模式的应用

2.1 需求说明

2.2 需求实现

2.2.1 账户抽象类

2.2.2 借款一个月

2.2.3 借款7天

2.2.4 测试类

三、模板方法模式总结

3.1 模板方法模式的优点

3.2 模板方法模式的缺点

3.3 模板方法模式的使用场景


一、模板方法模式介绍

1.1 模板方法模式的定义

模板方法模式(template method pattern)原始定义是:在操作中定义算法的框架,将一些步骤推迟到子类中。模板方法让子类在不改变算法结构的情况下重新定义算法的某些步骤。

模板方法中的算法可以理解为广义上的业务逻辑,并不是特指某一个实际的算法。定义中所说的算法的框架就是模板,包含算法框架的方法就是模板方法。

例如: 我们去医院看病一般要经过以下4个流程:挂号、取号、排队、医生问诊等,其中挂号、 取号 、排队对每个病人是一样的,可以在父类中实现,但是具体医生如何根据病情开药每个人都是不一样的,所以开药这个操作可以延迟到子类中实现。

模板方法模式是一种基于继承的代码复用技术,它是一种类行为模式。 模板方法模式其结构中只存在父类与子类之间的继承关系。


模板方法的作用主要是提高程序的复用性和扩展性:

  • 复用指的是,所有的子类可以复用父类中提供的模板方法代码
  • 扩展指的是,框架通过模板模式提供功能扩展点,让框架用户可以在不修改框架源码的情况下,基于扩展点定制化框架的功能。

1.2 模板方法模式的原理

模板方法模式的定位很清楚,就是为了解决算法框架这类特定的问题,同时明确表示需要使用继承的结构。

1.2.1 模板方法模式类图

1.2.2 类图角色说明

模板方法(Template Method)模式包含以下主要角色:

  • 抽象父类:定义一个算法所包含的所有步骤,并提供一些通用的方法逻辑。
  • 具体子类:继承自抽象父类,根据需要重写父类提供的算法步骤中的某些步骤。
  • 抽象类(Abstract Class):负责给出一个算法的轮廓和骨架。它由一个模板方法和若干个基本方法构成。
  1. 模板方法:定义了算法的骨架,按某种顺序调用其包含的基本方法。
  2. 基本方法:是实现算法各个步骤的方法,是模板方法的组成部分。

基本方法又可以分为三种:

  1. 抽象方法(Abstract Method) :一个抽象方法由抽象类声明、由其具体子类实现。
  2. 具体方法(Concrete Method) :一个具体方法由一个抽象类或具体类声明并实现,其子类可以进行覆盖也可以直接继承。
  3. 钩子方法(Hook Method) :在抽象类中已经实现,包括用于判断的逻辑方法和需要子类重写的空方法两种。一般钩子方法是用于判断的逻辑方法,这类方法名一般为isXxx,返回值类型为boolean类型。

1.2.3 示例代码

package main.java.cn.test.template.V1;

/**
 * @author ningzhaosheng
 * @date 2024/1/15 11:36:33
 * @description 抽象父类
 */
public abstract class AbstractClassTemplate {
    void step1(String key) {
        System.out.println("在模板类中 -> 执行步骤1");
        if (step2(key)) {
            step3();
        } else {
            step4();
        }
        step5();
    }

    boolean step2(String key) {
        System.out.println("在模板类中 -> 执行步骤2");
        if ("x".equals(key)) {
            return true;
        }
        return false;
    }

    abstract void step3();

    abstract void step4();

    void step5() {
        System.out.println("在模板类中 -> 执行步骤5");
    }

    void run(String key) {
        step1(key);
    }
}
package main.java.cn.test.template.V1;

/**
 * @author ningzhaosheng
 * @date 2024/1/15 11:37:48
 * @description 实现类A
 */
public class ConcreteClassA extends AbstractClassTemplate{
    @Override
    void step3() {
        System.out.println("在子类A中 -> 执行步骤 3");
    }

    @Override
    void step4() {
        System.out.println("在子类A中 -> 执行步骤 4");
    }
}

package main.java.cn.test.template.V1;

/**
 * @author ningzhaosheng
 * @date 2024/1/15 11:38:35
 * @description 实现类B
 */
public class ConcreteClassB extends AbstractClassTemplate {
    @Override
    void step3() {
        System.out.println("在子类B中 -> 执行步骤 3");
    }

    @Override
    void step4() {
        System.out.println("在子类B中 -> 执行步骤 4");
    }
}

package main.java.cn.test.template.V1;

/**
 * @author ningzhaosheng
 * @date 2024/1/15 11:39:16
 * @description 测试类
 */
public class Test {
    public static void main(String[] args) {
        AbstractClassTemplate concreteClassA = new ConcreteClassA();
        concreteClassA.run("");
        System.out.println("===========");
        AbstractClassTemplate concreteClassB = new ConcreteClassB();
        concreteClassB.run("x");
    }
}

二、模板方法模式的应用

2.1 需求说明

P2P公司的借款系统中有一个利息计算模块,利息的计算流程是这样的:

  1. 用户登录系统,登录时需要输入账号密码,如果登录失败(比如用户密码错误),系统需要给出提示。
  2. 如果用户登录成功,则根据用户的借款的类型不同,使用不同的利息计算方式进行计算。
  3. 系统需要显示利息。

2.2 需求实现

2.2.1 账户抽象类

package main.java.cn.test.template.V2;

/**
 * @author ningzhaosheng
 * @date 2024/1/15 11:43:55
 * @description 账户抽象类
 */
public abstract class Account {
    //step1 具体方法-验证用户信息是否正确
    public boolean validate(String account, String password) {
        System.out.println("账号: " + account + ",密码: " +
                password);
        if (account.equalsIgnoreCase("tom") && password.equalsIgnoreCase("123456")) {
            return true;
        } else {
            return false;
        }
    }

    //step2 抽象方法-计算利息
    public abstract void calculate();

    //step3 具体方法-显示利息
    public void display() {
        System.out.println("显示利息!");
    }

    //模板方法
    public void handle(String account, String password) {
        if (!validate(account, password)) {
            System.out.println("账户或密码错误!!");
            return;
        }
        calculate();
        display();
    }

}

2.2.2 借款一个月

package main.java.cn.test.template.V2;

/**
 * @author ningzhaosheng
 * @date 2024/1/15 11:44:54
 * @description 借款一个月
 */
public class LoanOneMonth extends Account {
    @Override
    public void calculate() {
        System.out.println("借款周期30天,利率为10%!");
    }
}

2.2.3 借款7天

package main.java.cn.test.template.V2;

/**
 * @author ningzhaosheng
 * @date 2024/1/15 11:45:27
 * @description 借款七天
 */
public class LoanSevenDays extends Account {
    @Override
    public void calculate() {
        System.out.println("借款周期7天,无利息!仅收取贷款金额1%的服务费!");
    }

    @Override
    public void display() {
        System.out.println("七日内借款无利息!");
    }

}

2.2.4 测试类

package main.java.cn.test.template.V2;

/**
 * @author ningzhaosheng
 * @date 2024/1/15 11:46:43
 * @description 测试类
 */
public class Test {
    public static void main(String[] args) {
        Account a1 = new LoanSevenDays();
        a1.handle("tom","12345");
        System.out.println("==========================");
        Account a2 = new LoanOneMonth();
        a2.handle("tom","123456");
    }
}

三、模板方法模式总结

3.1 模板方法模式的优点

  • 在父类中形式化的定义一个算法,而由它的子类来实现细节处理,在子类实现详细的处理代码时,并不会改变父类算法中步骤的执行顺序。
  • 模板方法可以实现一种反向的控制结构,通过子类覆盖父类的钩子方法,来决定某一个特定步骤是否需要执行。
  • 在模板方法模式中可以通过子类来覆盖父类的基本方法,不同的子类可以提供基本方法的不同实现,更换和增加新的子类很方便,符合单一职责原则和开闭原则。

3.2 模板方法模式的缺点

  • 对每个不同的实现都需要定义一个子类,这会导致类的个数增加,系统更加庞大,设计也更加抽象。
  • 父类中的抽象方法由子类实现,子类执行的结果会影响父类的结果,这导致一种反向的控制结构,它提高了代码阅读的难度。

3.3 模板方法模式的使用场景

  • 多个类有相同的方法并且逻辑可以共用时;
  • 将通用的算法或固定流程设计为模板,在每一个具体的子类中再继续优化算法步骤或流程步骤时;
  • 重构超长代码时,发现某一个经常使用的公有方法。

好了,本次分享就到这里,欢迎大家继续阅读《设计模式》专栏其他设计模式内容,如果有帮助到大家,欢迎大家点赞+关注+收藏,有疑问也欢迎大家评论留言!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

kibana查看和展示es数据

本文来说下使用kibana查看和展示es数据 文章目录 数据准备查询所有文档示例kibana查看和展示es数据 数据准备 可以使用es的命令或者java程序来往,es进行新增数据 查询所有文档示例 在 apifox 中,向 ES 服务器发 GET请求 :http://localhost:92…

Unity之触发器

目录 📕一、触发器概念 📕二、碰撞与触发的区别 📕三、触发器小实例 一、触发器概念 第一次玩侠盗猎车手是在小学,从那以后就开启了我的五星好市民之路。 下面是小编在小破站截的图,这是罪恶都市最开始的地方&a…

AI工具(20240116):Copilot Pro,Fitten Code等

Copilot Pro Copilot Pro是微软推出的Copilot的付费增强版本,通过提供优先访问GPT-4等最新AI模型,大大提升用户的创造力和工作效率。该服务可与Microsoft 365订阅捆绑使用,支持在Word、Excel等Office应用内直接使用Copilot功能,帮助用户更快速地起草文档、电子邮件和演示文稿等…

Kafka-消费者-KafkaConsumer分析-ConsumerCoordinator

在前面介绍了Kafka中Rebalance操作的相关方案和原理。 在KafkaConsumer中通过ConsumerCoordinator组件实现与服务端的GroupCoordinator的交互,ConsumerCoordinator继承了AbstractCoordinator抽象类。 下面我们先来介绍AbstractCoordinator的核心字段,如…

Linux下安装jdk、tomcat

linux下安装jdk、tomcat 一、linux下安装jdk1.1.下载Linux版本的JDK1.2.Linux安装JDk1.3.设置环境变量1.4.卸载JDK 二、linux下安装tomcat2.1.下载Linux版本的Tomcat2.2.在usr目录下新建tomcat目录2.3.进入到tomcat目录中解压下载的tomcat安装包2.4.配置环境变量-前提是已经安装…

HTML--CSS--盒子模型

在CSS模型中,所有元素都可以看做是一个盒子,这个盒子的组成部分: content 内容,文本或者图片 padding 内边距,定义内容到边框的距离 margin 外边距,定义当前元素与其他元素之间的距离 border 边框&#xff…

RK3566RK3568安卓11隐藏状态栏带接口

文章目录 前言一、创建全局变量二、设置应用添加隐藏导航栏按钮三、添加按钮功能四、动态隐藏还有显示功能五、创建系统导航栏广播接口总结 前言 关于Android系统的状态栏,不同的客户有不同的需求: 有些客户需要永久隐藏状态栏,有些客户需要在设置显示中…

春节假期出游一些很实用的手机技巧!这样玩,就很哇塞~

随着春节的脚步越来越近,无论是准备出游还是回家,你蠢蠢欲动的心是否已经拦不住了?华为 nova 12系列这些很哇塞的玩法你必须知道!这个新年让你旅行出圈有秘籍! 出发前智慧播报航班信息不错过。智慧播报的功能就很实…

c语言二维数组

系列文章目录 c语言二维数组 c语言二维数组 系列文章目录一、二维数组的定义一、二维数组的内存模型 一、二维数组的定义 int main() {//二维数组的定义int arr[3][4];arr[0][0]; arr[0][1]; arr[0][2]; arr[0][3]; arr[0][4];arr[1][0]; arr[1][1]; arr[1][2]; arr[1][3]; ar…

Qt 状态机框架:The State Machine Framework (一)

传送门: Qt 状态机框架:The State Machine Framework (一) Qt 状态机框架:The State Machine Framework (二) 一、什么是状态机框架 状态机框架提供了用于创建和执行状态图/表[1]的类。这些概念和表示法基于Harel的Statecharts:一种复杂系统的可视化形式&#xff…

JUC之可重入锁

📑前言 本文主要是【JUC】——JUC之可重入锁的文章,如果有什么需要改进的地方还请大佬指出⛺️ 🎬作者简介:大家好,我是听风与他🥇 ☁️博客首页:CSDN主页听风与他 🌄每日一句&…

.NET 8.0 发布到 IIS

如何在IIS(Internet信息服务)上发布ASP.NET Core 8? 在本文中,我假设您的 Windows Server IIS 上已经有一个应用程序池。 按照步骤了解在 IIS 环境下发布 ASP.NET Core 8 应用程序的技巧。 您需要设置代码以支持 IIS 并将项目配…

【Docker】在Windows操作系统安装Docker前配置环境

欢迎来到《小5讲堂》,大家好,我是全栈小5。 这是《Docker容器》序列文章,每篇文章将以博主理解的角度展开讲解, 特别是针对知识点的概念进行叙说,大部分文章将会对这些概念进行实际例子验证,以此达到加深对…

利用Lambda表达式实现vector中pair/结构体的排序

众所周知&#xff0c;对于vector<pair<int, int> >若直接使用sort排序&#xff0c;会默认按照pair的第一个关键字从小到大进行排序&#xff1a; #include <bits/stdc.h>using namespace std;int main() {vector<pair<int, int> > p;p.push_back…

CentOS 7 权限管理实战指南:用户管理相关命令详解

前言 掌握 CentOS 7 用户管理命令&#xff0c;轻松管理系统用户&#xff01;本文详细介绍了在 CentOS 7 系统中常用的用户管理命令&#xff0c;从创建和删除用户、修改用户属性&#xff0c;到密码管理和用户权限设置&#xff0c;一应俱全。无论你是 Linux 新手还是经验丰富的管…

Python 网络编程之粘包问题

【一】粘包问题介绍 【1】粘包和半包 粘包&#xff1a; 定义&#xff1a; 粘包指的是发送方发送的若干个小数据包被接收方一次性接收&#xff0c;形成一个大的数据包。原因&#xff1a; 通常是因为网络底层对数据传输的优化&#xff0c;将多个小数据包组合成一个大的数据块一次…

Ubantu 安装vscode配置c/c++环境

文章目录 安装VSCode注意 snap包冲突 安装C/C编译环境注意 进程锁占用 配置C开发环境安装插件配置tasks.json配置c_cpp_properties.json 配置调试环境配置 launch.json 安装VSCode 方式一&#xff1a;ubantu 软件里面直接安装 方式二&#xff1a;官网下载deb安装包https://cod…

Angular系列教程之zone.js和NgZone

文章目录 什么是zone.jsZone的工作原理Zone的常见用途NgZone&#xff1a;Angular中的zone.js使用NgZone使用NgZone执行代码使用NgZone外部检测 结论 什么是zone.js 在Angular中&#xff0c;zone.js是一个非常重要的库&#xff0c;它为我们提供了一种跟踪和管理异步操作的机制。…

【STM32】STM32学习笔记-USART串口收发HEX和文本数据包(29)

00. 目录 文章目录 00. 目录01. 串口简介02. 串口收发HEX数据包接线图03. 串口收发HEX数据包示例104. 串口收发HEX数据包示例205. 串口收发文本数据包接线图06. 串口收发文本数据包示例07. 程序示例下载08. 附录 01. 串口简介 串口通讯(Serial Communication)是一种设备间非常…

AI与区块链的完美交融创新时代的双重引擎

每个投资者都梦想早日进入“下一个亚马逊、苹果或比特币”&#xff0c;以追求代际财富。 然而&#xff0c;这些机会很少而且相距甚远&#xff0c;而且正如每一个虔诚的加密货币本地人都知道的那样&#xff0c;这条道路上常常布满了失败的项目、失信的承诺和波动。 但在 2023 …