模板方法模式介绍

news2024/12/23 18:47:57

目录

一、模板方法模式介绍

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 模板方法模式的使用场景

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

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

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

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

相关文章

helm---自动化一键部署

什么是helm?? 在没有这个helm之前,deployment service ingress helm的作用就是通过打包的方式,把deployment service ingress 这些打包在一块,一键式部署服务,类似于yum 官方提供的一个类似于安装仓库的功能,可以实…

Unity学习之坦克游戏制作(1)开始场景的制作

文章目录 1. 实现效果2. 场景装饰2.1 创建场景2.2 拖入场景地板 3 开始界面3.1 导入UI3.2 创建面板基类3.2.1 开始按钮 4 设置界面5 音效数据逻辑5.1 音效数据可持久化5.2 声明音效管理的主要变量5.3 声明数据管理器5.4 在设置面板的数据初始化5.5 提供API给外部 6 排行榜界面6…

​WordPress顶部管理工具栏怎么添加一二级自定义菜单?

默认情况下,WordPress前端和后台页面顶部都有一个“管理工具栏”,左侧一般就是站点名称、评论、新建,右侧就是您好,用户名称和头像。那么我们是否可以在这个管理工具栏中添加一些一二级自定义菜单呢? 其实&#xff0c…

JavaScript库jquery的使用方法

"写更少,做更多"是jquery的设计理念,jquery是一个兼容多浏览器的JavaScript库,利用jquery的语法设计能使开发更便捷。 网页添加jquery的方法:1.从jquery.com下载库;2.从CDN中载入库(示例使用)&a…

线性代数:矩阵运算(加减、数乘、乘法、幂、除、转置)

目录 加减 数乘 矩阵与矩阵相乘 矩阵的幂 矩阵转置 方阵的行列式 方阵的行列式,证明:|AB| |A| |B| 加减 数乘 矩阵与矩阵相乘 矩阵的幂 矩阵转置 方阵的行列式 方阵的行列式,证明:|AB| |A| |B|

项目管理中如何有效沟通?项目管理有效沟通指南

无论是少数人的小型企业还是拥有数十名员工的大公司,有效的沟通对于确保每个人都参与并准备好在项目中实现相同的目标至关重要。 然而,由于沟通不畅,似乎在翻译中总是丢失一些东西。事实上,根据布兰迪斯大学的一项研究&#xff0c…

k8s集群加入一个master2--kubeadm方式

已经有一个集群: 192.168.206.138 master 192.168.206.136 k8s-node1 192.168.206.137 k8s-node2 kubectl get nodes -o wide 新加入一个master2节点 192.168.206.139 master2 一、初始化系统参数 139 master2 上 #在136、137、138上添加hosts“” echo "…

MSG3D

论文在stgcn与sta-lstm基础上做的。下面讲一下里面的方法: 1.准备工作 符号。这里是对符号进行解释。 一个人体骨骼图被记为G(v,E) 图卷积: 图卷积定义 考虑一种常用于处理图像的标准卷积神经网络 (CNN)。输入是像素网格。每个像素都有一个数据值向…

protobuf 之诡异的文件流与压缩

只接上干货,内容较干。文章大概需要花费5分钟简单了解下。 1、Gzip 直接看源码头文件如上图。压缩对象 GzipOutputStream ,通过函数操作可以看到整个文件流是比较完整并清晰。 因为它显示清晰包含了 从初始化 到 flush 到 close 的显示调用 2、Ostream…

同样是IT行业,测试和开发薪资真就差这么大吗?

🔥 交流讨论:欢迎加入我们一起学习! 🔥 资源分享:耗时200小时精选的「软件测试」资料包 🔥 教程推荐:火遍全网的《软件测试》教程 📢欢迎点赞 👍 收藏 ⭐留言 &#x1…

ESP32-TCP服务端(Arduino)

将ESP32设置为TCP服务器 介绍 TCP(Transmission Control Protocol)传输控制协议,是一种面向连接的(一个客户端对应一个服务端)、可靠的传输层协议。在TCP的工作原理中,它会将消息或文件分解为更小的片段&a…

c++:string相关的oj题(把字符串转换成整数、344.反转字符串、387. 字符串中的第一个唯一字符、917. 仅仅反转字母)

文章目录 1.把字符串转换成整数题目详情代码思路 2. 344.反转字符串题目详情代码1思路1代码2思路 3. 387. 字符串中的第一个唯一字符题目详情代码思路 4. 917. 仅仅反转字母题目详情代码思路 1.把字符串转换成整数 传送门 题目详情 代码 class Solution { public:int StrToI…

DDOD(Disentangle Your Dense Object Detector)解析

paper:Disentangle Your Dense Object Detector official implementation:https://github.com/zehuichen123/DDOD third-party implementation:https://github.com/open-mmlab/mmdetection/tree/main/configs/ddod 存在的问题 现有的目标…

Docker命令---搜索镜像

介绍 使用docker命令搜索镜像。 命令 docker search 镜像命令:版本号示例 以搜索ElasticSearch镜像为例 docker search ElasticSearch

华而有实,维乐Prevail Glide带你领略风景线,成为风景线~

大家都知道呢!骑行,不仅是一种运动,更是一种生活态度。在骑行装备的世界里,一个好的坐垫对于骑行的舒适度和安全性至关重要。那今天,我要为大家推荐一款备受赞誉的坐垫——维乐坐垫美学系列-Prevail Glide。    为…

学习笔记——克里金插值

有一篇大神的文章写得非常的具体, https://xg1990.com/blog/archives/222 下面写下一些学习笔记: 1、关于克里金插值的基本原理 克里金插值来源于地理学,它的前提是地理学第一定律:所有事物都与其他事务相关,但是近…

Linux性能监控命令-top

简介 top 命令用于实时监视系统的性能和进程信息。它提供了一个动态的、交互式的界面,列出了当前运行的进程,并显示了它们的 CPU 和内存使用情况。通过该命令可以对硬件性能瓶颈做出基本判断。 1. 语法 top top [参数] top 有 2 种指定参数方式&#xff…

Python 生成 图片网页列表 显示路径和建立时间 笔记

Python 一键 生成 图片网页列表 显示路径和建立时间 (方便查看复制路径、重复一键生成) 支持格式:jpg \png\ svg\ webp 图片网页列表 图示: 参考代码: # -*- coding: utf-8 -*- import os import datetime# 指定图片…

自己构建webpack+vue3+ts

先看看我的目录结构(我全局使用TS): 一、安装配置webpack打包 安装esno npm install esnoesno 是基于 esbuild 的 TS/ESNext node 运行时,有了它,就可以直接通过esno *.ts的方式启动脚本,package.json中添加 type:…

【动态规划】【C++算法】801. 使序列递增的最小交换次数

作者推荐 【动态规划】【广度优先搜索】【状态压缩】847 访问所有节点的最短路径 本文涉及知识点 动态规划汇总 数组 LeetCode801使序列递增的最小交换次数 我们有两个长度相等且不为空的整型数组 nums1 和 nums2 。在一次操作中,我们可以交换 nums1[i] 和 num…