行为型设计模式02-模板方法模式

news2024/11/25 23:01:50

🧑‍💻作者:猫十二懿

🏡账号:CSDN 、个人博客 、Github

🎊公众号:猫十二懿

模板方法模式

1、模板方法模式介绍

模板方法模式是一种行为型设计模式,定义了一个算法的框架,将其中一些步骤延迟到子类中实现。它使得子类可以在不改变算法结构的情况下,重新定义算法中某些步骤的具体实现方式。

模板方法模式通常由两部分组成:

  1. 抽象模板类(Abstract Template Class):定义了算法的框架和每个步骤应该如何执行,但并不实现全部方法,并且该类中的某些方法可以有默认实现。
  2. 具体实现类(Concrete Implementation Class):实现抽象模板类中的未实现方法,以及定义算法中的一些细节。

2、具体例子

考试的试卷,每个人都是考同一个试卷,但是老师将题目写在黑板上,同学们自己抄试卷。

2.1 不使用模板方法

学生甲抄写的试卷:

package com.shier.template;

/**
 * 学生甲抄的试卷
 * @author Shier
 * CreateTime 2023/4/22 22:03
 */
public class TestPaperA {
    //试题1
    public void testQuestion1() {
        System.out.println(" 杨过得到,后来给了郭靖,炼成倚天剑、屠龙刀的玄铁可能是[ ] "+
            " a.球磨铸铁 b.马口铁 c.高速合金钢 d.碳素纤维 ");
        System.out.println("答案:b");
    }
    //试题2
    public void testQuestion2() {
        System.out.println(" 杨过、程英、陆无双铲除了情花,造成[ ] "+
            "a.使这种植物不再害人 b.使一种珍稀物种灭绝 c.破坏了那个生物圈的生态平衡 d.造成该地区沙漠化  ");
        System.out.println("答案:a");
    }
    //试题3
    public void testQuestion3() {
        System.out.println(" 蓝凤凰致使华山师徒、桃谷六仙呕吐不止,如果你是大夫,会给他们开什么药[ ] "+
            "a.阿司匹林 b.牛黄解毒片 c.氟哌酸 d.让他们喝大量的生牛奶 e.以上全不对   ");
        System.out.println("答案:c");
    }
}

学生乙的抄写的试卷:

/**
 * 学生乙抄的试卷
 *
 * @author Shier
 * CreateTime 2023/4/22 22:03
 */
public class TestPaperB {
    //试题1
    public void testQuestion1() {
        System.out.println(" 杨过得到,后来给了郭靖,炼成倚天剑、屠龙刀的玄铁可能是[ ] " +
                " a.球磨铸铁 b.马口铁 c.高速合金钢 d.碳素纤维 ");
        System.out.println("答案:d");
    }

    //试题2
    public void testQuestion2() {
        System.out.println(" 杨过、程英、陆无双铲除了情花,造成[ ] " +
                "a.使这种植物不再害人 b.使一种珍稀物种灭绝 c.破坏了那个生物圈的生态平衡 d.造成该地区沙漠化  ");
        System.out.println("答案:b");
    }

    //试题3
    public void testQuestion3() {
        System.out.println(" 蓝凤凰致使华山师徒、桃谷六仙呕吐不止,如果你是大夫,会给他们开什么药[ ] " +
                "a.阿司匹林 b.牛黄解毒片 c.氟哌酸 d.让他们喝大量的生牛奶 e.以上全不对   ");
        System.out.println("答案:a");
    }
}

测试类:

/**
 *
 * @author Shier
 * CreateTime 2023/4/22 22:05
 */
public class Test {

   public static void main(String[] args){

      System.out.println("学生甲抄的试卷:");
        TestPaperA studentA = new TestPaperA();
        studentA.testQuestion1();
        studentA.testQuestion2();
        studentA.testQuestion3();

        System.out.println("学生乙抄的试卷:");
        TestPaperB studentB = new TestPaperB();
        studentB.testQuestion1();
        studentB.testQuestion2();
        studentB.testQuestion3();
   }
}

结果如下:

image-20230422220521549

观察发现:学生甲和学生乙两个抄试卷类非常类似,除了答案不同,没什么不一样,这样写又容易错,又难以维护。

2.2 使用模板方法模式

最终使用模板方法的得出的UML类图如下:
在这里插入图片描述

使用继承,父类(抽象类)就应该要成为子类的模板,所有重复的代码都应该要上升到父类去,而不是让每个子类都去重复。

当我们要完成在某一细节层次一致的一个过程或一系列步骤,但其个别步骤在更详细的层次上的实现可能不同时,我们通常考虑用模板方法模式来处理。

抽象类TestPaper:

/**
 * @author Shier
 * CreateTime 2023/4/22 22:11
 */
public abstract class TestPaper {
    // 给继承TestPaper的子类来重写,返回不同的答案
    protected abstract String answer1();
    protected abstract String answer2();
    protected abstract String answer3();

    public void testQuestion1() {
        System.out.println(" 杨过得到,后来给了郭靖,炼成倚天剑、屠龙刀的玄铁可能是[ ] " +
                " a.球磨铸铁 b.马口铁 c.高速合金钢 d.碳素纤维 ");
        System.out.println("答案:" + this.answer1());
    }

    //试题2
    public void testQuestion2() {
        System.out.println(" 杨过、程英、陆无双铲除了情花,造成[ ] " +
                "a.使这种植物不再害人 b.使一种珍稀物种灭绝 c.破坏了那个生物圈的生态平衡 d.造成该地区沙漠化  ");
        System.out.println("答案:" + this.answer2());
    }

    //试题3
    public void testQuestion3() {
        System.out.println(" 蓝凤凰致使华山师徒、桃谷六仙呕吐不止,如果你是大夫,会给他们开什么药[ ] " +
                "a.阿司匹林 b.牛黄解毒片 c.氟哌酸 d.让他们喝大量的生牛奶 e.以上全不对   ");
        System.out.println("答案:" + this.answer3());
    }
}

此时的甲乙同学的类,就相当于一个答题卡一样,只要把答案写上去,就可以,就不要再去抄题目。

/**
 * 学生甲抄的试卷
 * @author Shier
 * CreateTime 2023/4/22 22:03
 */
public class TestPaperA extends TestPaper{
    /**
     * 第一题答案
     * @return
     */
    @Override
    protected String answer1() {
        return "b";
    }

    /**
     * 第二题
     * @return
     */
    @Override
    protected String answer2() {
        return "a";
    }

    /**
     * 第三题
     * @return
     */
    @Override
    protected String answer3() {
        return "c";
    }

}
/**
 * 学生乙抄的试卷
 *
 * @author Shier
 * CreateTime 2023/4/22 22:03
 */
public class TestPaperB extends TestPaper{
    /**
     * 第一题答案
     * @return
     */
    @Override
    protected String answer1() {
        return "b";
    }

    /**
     * 第二题
     * @return
     */
    @Override
    protected String answer2() {
        return "a";
    }

    /**
     * 第三题
     * @return
     */
    @Override
    protected String answer3() {
        return "c";
    }
}

测试类:

/**
 *
 * @author Shier
 * CreateTime 2023/4/22 22:03
 */
public class Test {

   public static void main(String[] args){

      System.out.println("学生甲抄的试卷:");
        TestPaper studentA = new TestPaperA();
        studentA.testQuestion1();
        studentA.testQuestion2();
        studentA.testQuestion3();

        System.out.println("学生乙抄的试卷:");
        TestPaper studentB = new TestPaperB();
        studentB.testQuestion1();
        studentB.testQuestion2();
        studentB.testQuestion3();
   }
}

3、模板方法

模板方法的结构图:

image-20230422222004181

AbstractClass是抽象类,其实也就是一个抽象模板,定义并实现了一个模板方法。这个模板方法一般是一个具体方法,它给出了一个顶级逻辑的骨架,而逻辑的组成步骤在相应的抽象操作中,推迟到子类实现。顶级逻辑也有可能调用一些具体方法。

ConcreteClass,实现父类所定义的一个或多个抽象方法。每一个AbstractClass都可以有任意多个ConcreteClass与之对应,而每一个ConcreteClass都可以给出这些抽象方法(也就是顶级逻辑的组成步骤)的不同实现,从而使得顶级逻辑的实现各不相同。

4、总结

模板方法模式是通过把不变行为搬移到超类,去除子类中的重复代码来体现它的优势。

模板方法模式优点:

  1. 避免重复代码:将公共的方法提取到抽象模板类中,子类不再需要编写相同的代码段。
  2. 提高代码可扩展性:子类可以通过实现抽象模板类中的具体方法来改变算法的实现方式,从而达到扩展算法的目的,而不会影响到算法的整体结构。
  3. 降低代码耦合度:算法的框架和具体实现分别由抽象模板类和其子类实现,它们之间通过接口或者抽象父类进行交互,不直接依赖于具体的实现类。

缺点:

  1. 违反了单一职责原则:抽象模板类将算法的各个步骤定义在一个类中,其中包含了不同的逻辑分支,在一些情况下可能会使得该类变得比较庞大,难以维护和拓展。
  2. 可能导致代码复杂性增加:模板方法模式要求实现类必须提供某些具体的实现方法,这可能会导致实现类在实现这些方法时需要考虑更多的细节问题,从而增加了代码的复杂度。
  3. 破坏了封装性:实现类需要实现抽象模板类中定义的某些方法,这意味着实现类需要访问抽象模板类中的一些属性和方法,从而破坏了抽象模板类的封装性。

当不变的和可变的行为在方法的子类实现中混合在一起的时候,不变的行为就会在子类中重复出现。我们通过模板方法模式把这些行为搬移到单一的地方,这样就帮助子类摆脱重复的不变行为的纠缠。

5、模板方法模式和原型模式的区别

我认为都是不断的 new 同一个对象,来初始化不同的数据来得到不同的内容,但是具体的区别如下所述

模板方法模式和原型模式是两种不同的设计模式,它们的作用和应用场景不同。

模板方法模式是一种行为型设计模式,它定义一个操作中的算法骨架,并允许子类为一个或多个步骤提供实现,而不需要改变算法的结构。模板方法模式的主要目的是在保持算法结构不变的同时,允许子类为某些步骤提供具体实现,从而实现代码复用和扩展。

原型模式是一种创建型设计模式,它通过复制现有对象来创建新对象,从而避免了从头开始创建新对象的代码。原型模式通过使用原型管理器来存储原型对象,并在需要时获取原型对象的副本,以避免多次创建相同的对象。

模板方法模式和原型模式的区别:

区别模板方法模式原型模式
目的不同保持算法结构不变的同时,允许子类为某些步骤提供具体实现通过复制现有对象来创建新对象,避免了从头开始创建新对象的代码
适用场景不同具有相同算法结构但某些步骤具体实现可能不同的场景,例如算法、流程和框架的设计中创建大量相似对象的场景,例如在图形界面中创建图形对象
实现方式不同通过定义抽象类和具体子类实现通过复制现有对象来创建新对象

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

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

相关文章

现代化个人博客系统 ModStartBlog v7.4.0 暗黑模式跟随系统,随机博客获取

ModStart 是一个基于 Laravel 模块化极速开发框架。模块市场拥有丰富的功能应用,支持后台一键快速安装,让开发者能快的实现业务功能开发。 系统完全开源,基于 Apache 2.0 开源协议。 功能特性 丰富的模块市场,后台一键快速安装 …

基于GMM的一维时序数据平滑算法

本文将介绍我们使用高斯混合模型(GMM)算法作为一维数据的平滑和去噪算法。 假设我们想要在音频记录中检测一个特定的人的声音,并获得每个声音片段的时间边界。例如,给定一小时的流,管道预测前10分钟是前景(我们感兴趣的人说话),然…

OSPF协议知识点

OSPF 七种状态机 down--- 关闭状态 ---- 一旦启动了 OSPF 协议,则发出 hello 包,并进入下一状态 init---- 初始化状态 ---- 收到的 hello 包中,存在自己的 RID 值,则进入下一状态 2-way---- 双向通讯状态 ----- 邻居关系建立的…

Linux kernel调试 SPI NORFLASH--W25Q128

W25Q128介绍 W25Q128 是华邦公司推出的一款 SPI 接口的 NOR Flash 芯片,其存储空间为 128Mbit,相当于 16M 字节。W25Q128 可以支持 SPI 的模式 0 和模式 3,也就是 CPOL0/CPHA0 和CPOL1/CPHA1 这两种模式。      Flash 写入数据时和 EEPR…

【Linux初阶】基础IO - 文件操作(使用系统接口实现) | vim批量注释代码

🌟hello,各位读者大大们你们好呀🌟 🍭🍭系列专栏:【Linux初阶】 ✒️✒️本篇内容:重新理解文件和文件操作,C语言实现的简单文件操作,文本初始权限,系统接口介…

【spring源码系列-01】spring底层源码整体概述

JVM系列整体栏目 内容链接地址【一】spring源码整体概述https://blog.csdn.net/zhenghuishengq/article/details/130940885 初识虚拟机与java虚拟机 一,spring源码整体概述1,初步概述2,扩展点机制3,核心方法refresh4,B…

【wpf】xaml 中的参数复用

背景 xaml中有几种复用的方式: 有时在xaml中,我们需要复用一些参数,比如 固定的一个值。 有时是固定的一个样式。 资源,sys的引入 有时多个控件都要设置一个高度,我可以引入sys 声明 我就使用这个吧&#xff1a…

扬帆出海正当时,企业应该做好哪些准备?

在跨境出海的时代大潮中,想要拓展海外市场的中国企业,应该事先做好哪些准备? 中国企业出海的新格局 首先来看一组令人振奋的数据。来自中国信通院的数据显示,在2020年的时候,中国数字经济的规模就达到了39.2万亿元人民…

本地Linux搭建web服务并发布公网访问

文章目录 前言1. 本地环境服务搭建2. 局域网测试访问3. 内网穿透3.1 ubuntu本地安装cpolar内网穿透3.2 创建隧道3.3 测试公网访问 4. 配置固定二级子域名4.1 保留一个二级子域名4.2 配置二级子域名4.3 测试访问公网固定二级子域名 转载自cpolar极点云的文章:在Ubunt…

玩转华为云Astro低代码体验季

目录 Astro轻应用应用场景 零代码应用构建 轻应用构建 行业应用构建 业务大屏构建 使用体验 功能建议 总体评价 Astro轻应用(Astro Zero,简称AstroZero)是华为云为行业客户、合作伙伴、开发者量身打造的低代码/零代码应用开发平台&#xff0c…

C++ A lambda function

lambda 函数是 C 中的匿名函数,可以内联定义并用作函数对象。 下面是定义 lambda 函数的一般语法: [capture list] (parameter list) -> return type { function body }lambda 语法的每个部分: - capture list:这是一个可选的…

R实践——【rgplates】功能函数解析

【rgplates】功能函数解析 1. 板块和特征重建2. 构造模型表示2.1 用法2.2 参数2.3 值2.4 示例 3. 实用工具3.1 用法3.2 参数3.3. 值3.4 示例 1. 板块和特征重建 一切与几何形状重建到过去状态有关的东西 reconstruct():重建地理特征 详见R语言实践——古今地理坐…

4. WebGPU 存储缓冲区 (WebGPU Storage Buffers)

这篇文章是关于存储缓冲区的&#xff0c;我们从上一篇文章暂停的地方继续。 存储缓冲区在许多方面类似于统一缓冲区。如果我们所做的只是将 JavaScript 中的 UNIFORM 更改为 STORAGE 并将 WGSL 中的 var 更改为 var<storage, read> &#xff0c;那么上一页中的示例就可以…

Zabbix“专家坐诊”第193期问答汇总

问题一 Q&#xff1a;大佬们&#xff0c;怎么才能将zabbix-server接收到的数据全部展示出来呢&#xff1f;目前我的显示数据无法全部显示。 A&#xff1a;这个是用zabbix_sender发送过来的&#xff1f;确认下数据中是否包含空格等&#xff0c;如果有空格使用反斜杠转义或者单…

uniapp内置组件

目录 3.1、视图容器 view scroll-view swiper match-media 3.2、表单组件 form input App平台iOS端软键盘上方横条去除方案 关于软键盘弹出的逻辑说明 关于软键盘收起的逻辑说明 picker 3.3、 路由与页面跳转 navigator组件 3.4、 地图 map 3.1、视图容器 所有…

2.5. 重载与覆盖

在 Java 中&#xff0c;方法的重载&#xff08;Overloading&#xff09;和覆盖&#xff08;Overriding&#xff09;是两个重要的概念。它们都涉及到方法的定义与使用&#xff0c;但作用和规则有所不同。 重载&#xff08;Overloading&#xff09; 重载是指在同一个类中定义多…

2023年6月18日DAMA-CDGA/CDGP数据治理认证报名到这里

DAMA认证为数据管理专业人士提供职业目标晋升规划&#xff0c;彰显了职业发展里程碑及发展阶梯定义&#xff0c;帮助数据管理从业人士获得企业数字化转型战略下的必备职业能力&#xff0c;促进开展工作实践应用及实际问题解决&#xff0c;形成企业所需的新数字经济下的核心职业…

在家远程使用公司用友ERP财务软件 【远程办公】

文章目录 前言1.本地访问简介2. cpolar内网穿透3. 公网远程访问4. 固定公网地址 转发自cpolar极点云的文章&#xff1a;外网远程访问公司内网用友畅捷通T财务软件 – 远程办公 前言 用友畅捷通T适用于异地多组织、多机构对企业财务汇总的管理需求&#xff1b;全面支持企业对远…

webpack简单的搭建和使用(1)

随便创建一个空的文件夹&#xff0c;例如说&#xff1a;explore 然后我们测试一下我们的node是否存在 可以正确打印出版本 我们再次输入&#xff1a;npm init -y 创建一个package.json文件 出现这样的情况就成功了 然后我们要安装webpack在终端上输入命令&#xff1a; npm i …

数据结构图的基础概念

1、图的概念 图(Graph)&#xff1a;是由顶点的有穷非空集合和顶点之间边的集合组成。顶点(Vertex)&#xff1a;图中的数据元素。边(Edge)&#xff1a;顶点之间的逻辑关系,边可以是有向的或无向的&#xff0c;也可以带有权重&#xff08;可以表示距离&#xff0c;花费等&#xf…