设计模式——模板模式

news2024/11/25 2:40:28

  导航: 

【黑马Java笔记+踩坑汇总】JavaSE+JavaWeb+SSM+SpringBoot+瑞吉外卖+SpringCloud+黑马旅游+谷粒商城+学成在线+设计模式+牛客面试题

目录

模板模式

1、基本介绍

 2、模板模式解决豆浆制作问题

3、钩子方法

4、Spring 框架AbstractApplicationContext抽象类


模板模式

1、基本介绍

  • 1)模板方法模式(Template Method Pattern),又叫模板模式(Template Pattern),在一个抽象类公开定义了执行它的方法的模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行
  • 2)简单说,模板方法模式定义一个操作中的算法的骨架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构,就可以重定义该算法的某些特定步骤
  • 3)这种类型的设计模式属于行为型模式(用于描述对象之间的通信和责任分配)。

实现方式:抽象类有一个模板方法和其他行为方法,模板方法按流程调用各行为方法(抽象或非抽象);具体子类重写抽象的行为方法。

对原理类图的说明——即模板方法模式的角色和职责

  • AbstractClass抽象类中实现了模板方法,定义了算法的骨架,具体子类需要去实现其抽象方法或重写其中方法
  • ConcreteClass实现了抽象方法,已完成算法中特定子类的步骤

注意事项和细节

  • 1)基本思想:算法只存在于一个地方,也就是在父类中,容易修改。需要修改算法时,只要修改父类的模板方法或者已经实现的某些步骤,子类就会继承这些修改
  • 2)实现了最大化代码复用。父类的模板方法和已实现的某些步骤会被子类继承而直接使用
  • 3)既统一了算法,也提供了很大的灵活性。父类的模板方法确保了算法的结构保持不变,同时由子类提供部分步骤的实现
  • 4)不足之处:每一个不同的实现都需要一个子类实现,导致类的个数增加,使得系统更加庞大
  • 5)一般模板方法都加上final关键字,防止子类重写模板方法
  • 6)使用场景:当要完成在某个过程,该过程要执行一系列步骤,这一系列的步骤基本相同,但其个别步骤在实现时可能不同,通常考虑用模板方法模式来处理

 2、模板模式解决豆浆制作问题

编写制作豆浆的程序,说明如下:

  • 1)制作豆浆的流程选材 ----> 添加配料 ----> 浸泡 ----> 放到豆浆机打碎
  • 2)通过添加不同的配料,可以制作出不同口味的豆浆
  • 3)选材、浸泡和放到豆浆机打碎这几个步骤是一个模板方法,对于制作每种口味的豆浆都是一样的
  • 4)请使用模板方法模式完成

说明:因为模板方法模式比较简单,很容易就想到这个方案,因此就直接使用,不再使用传统的方案来引出模板方法模式

 

核心代码

/**
 * 抽象方法
 */
public abstract class SoyaMilk {
    /**
     * 模板方法,定义为final禁止覆写
     */
    public final void make() {
        System.out.println(">>>>>>豆浆制作开始<<<<<<");
        useSoyBean();
        addIngredients();
        soak();
        mash();
        System.out.println(">>>>>>豆浆制作结束<<<<<<");
    }
// 同包可见、对其他包下的子类可见。
    protected void useSoyBean() {
        System.out.println("Step1. 选用上好的黄豆.");
    }
//添加原材料是抽象方法,因为不同豆浆原材料不一样
    protected abstract void addIngredients();

    protected void soak() {
        System.out.println("Step3. 对黄豆和配料进行水洗浸泡.");
    }

    protected void mash() {
        System.out.println("Step4. 将充分浸泡过的黄豆和配料放入豆浆机中,开始打豆浆.");
    }
}
/**
 * 花生豆浆
 */
public class PeanutSoyaMilk extends SoyaMilk {
    public PeanutSoyaMilk() {
        System.out.println("============花生豆浆============");
    }
    @Override
    protected void addIngredients() {
        System.out.println("Step2. 加入上好的花生.");
    }
}
/**
 * 红豆豆浆
 */
public class RedBeanSoyaMilk extends SoyaMilk {
    public RedBeanSoyaMilk() {
        System.out.println("============红豆豆浆============");
    }
    @Override
    protected void addIngredients() {
        System.out.println("Step2. 加入上好的红豆.");
    }
}
/**
 * 芝麻豆浆
 */
public class SesameSoyaMilk extends SoyaMilk {
        public SesameSoyaMilk() {
        System.out.println("============芝麻豆浆============");
    }
    @Override
    protected void addIngredients() {
        System.out.println("Step2. 加入上好的芝麻.");
    }
}

客户端调用模板方法

SoyaMilk peanutSoyaMilk = new PeanutSoyaMilk();
peanutSoyaMilk.make();
SoyaMilk redBeanSoyaMilk = new RedBeanSoyaMilk();
redBeanSoyaMilk.make();
SoyaMilk sesameSoyaMilk = new SesameSoyaMilk();
sesameSoyaMilk.make();
/*
============花生豆浆============
>>>>>>豆浆制作开始<<<<<<
Step1. 选用上好的黄豆.
Step2. 加入上好的花生.
Step3. 对黄豆和配料进行水洗浸泡.
Step4. 将充分浸泡过的黄豆和配料放入豆浆机中,开始打豆浆.
>>>>>>豆浆制作结束<<<<<<
============红豆豆浆============
>>>>>>豆浆制作开始<<<<<<
Step1. 选用上好的黄豆.
Step2. 加入上好的红豆.
Step3. 对黄豆和配料进行水洗浸泡.
Step4. 将充分浸泡过的黄豆和配料放入豆浆机中,开始打豆浆.
>>>>>>豆浆制作结束<<<<<<
============芝麻豆浆============
>>>>>>豆浆制作开始<<<<<<
Step1. 选用上好的黄豆.
Step2. 加入上好的芝麻.
Step3. 对黄豆和配料进行水洗浸泡.
Step4. 将充分浸泡过的黄豆和配料放入豆浆机中,开始打豆浆.
>>>>>>豆浆制作结束<<<<<<
*/

3、钩子方法

在模板方法模式的父类中,我们可以定义一个方法,它默认不做任何事,子类可以视情况要不要覆盖它,该方法称为“钩子”

还是用上面做豆浆的例子来讲解,比如,我们还希望制作纯豆浆,不添加任何的配料,请使用钩子方法对前面的模板方法进行改造

抽象类和具体类

//抽象模板类
public abstract class SoyaMilk {
//模板方法
    public final void make() {
        // ...
//如果钩子方法决定加配料,就加配料;否则不执行加配料操作。
        if (customAddIngredients()) {
            addIngredients();
        }
        // ...
    }
//钩子方法,决定是否需要添加配料。默认情况是加配料。
    boolean customAddIngredients() {
        return true;
    }
    // ...
}

/**
 * 纯豆浆
 */
public class PureSoyaMilk extends SoyaMilk {
    public PureSoyaMilk() {
        System.out.println("============纯豆浆============");
    }

    @Override
    protected void addIngredients() {
        // 空实现即可
    }

    @Override
    protected Boolean customAddIngredients() {
        return false;
    }
}

客户端,测试钩子方法

SoyaMilk pureSoyaMilk = new PureSoyaMilk();
pureSoyaMilk.make();
/*
============纯豆浆============
>>>>>>豆浆制作开始<<<<<<
Step1. 选用上好的黄豆.
Step3. 对黄豆和配料进行水洗浸泡.
Step4. 将充分浸泡过的黄豆和配料放入豆浆机中,开始打豆浆.
>>>>>>豆浆制作结束<<<<<<
*/

4、Spring 框架AbstractApplicationContext抽象类

AbstractApplicationContext.java中有一个refresh()方法就是模板方法,它用于根据流程调用aop代理创建、bean生命周期初始化、属性注入等启动并初始化Spring应用上下文的方法。

AbstractApplicationContext抽象类是ApplicationContext接口的一种默认实现,提供了一些通用的应用上下文功能,同时也为其他具体的应用上下文实现类提供了一些可扩展的方法。

应用上下文:负责管理各种bean以及它们之间的关系,并对它们进行生命周期的管理。 

// 模板方法
public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        prepareRefresh();
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
        prepareBeanFactory(beanFactory);
        try {
            postProcessBeanFactory(beanFactory); // 钩子方法
            invokeBeanFactoryPostProcessors(beanFactory);
            registerBeanPostProcessors(beanFactory);
            initMessageSource();
            initApplicationEventMulticaster();
            onRefresh(); // 钩子方法
            registerListeners();
            finishBeanFactoryInitialization(beanFactory);
            finishRefresh();
        }
        catch (BeansException ex) {
            if (logger.isWarnEnabled()) {
                logger.warn("Exception encountered during context initialization - " +
                            "cancelling refresh attempt: " + ex);
            }
            destroyBeans();
            cancelRefresh(ex);
            throw ex;
        }
        finally {
            resetCommonCaches();
        }
    }
}
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
    refreshBeanFactory(); // 抽象方法
    ConfigurableListableBeanFactory beanFactory = getBeanFactory(); // 抽象方法
    if (logger.isDebugEnabled()) {
        logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
    }
    return beanFactory;
}
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
}
protected void onRefresh() throws BeansException {
    // For subclasses: do nothing by default.
}

 

 

 

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

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

相关文章

C语言从入门到精通第16天(指针的定义与基本使用)

指针的定义与基本使用 什么是指针&#xff1f;指针变量的定义指针变量的基本使用 什么是指针&#xff1f; 在使用指针之前我们需要对指针进行初步的了解&#xff0c;首先我们要知道什么是指针&#xff1f; 通过前面的学习我们已经知道了内存的存储方式&#xff0c;他是通过一…

【LeetCode股票买卖系列:121. 买卖股票的最佳时机 | 一次遍历 | 暴力递归=>记忆化搜索=>动态规划】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

在群晖NAS上快速搭建属于自己的Git Server

群晖NAS套件中心是有Git Server套件的&#xff0c;只要在套件中心安装即可。但是需要注意的是&#xff1a; git 相关的命令需要使用 SSH 客户端连接到NAS上进操作。配置git时需要使用 管理员权限账户&#xff0c;而 push / fetch 使用的账户一般都为普通用户&#xff0c;一定要…

ChatGPT提示词工程(一):Guidelines

目录 一、说明二、安装环境三、Guidelines准则一&#xff1a;写出明确而具体的说明方法1&#xff1a;使用分隔符清楚地表示输入的不同部分方法2&#xff1a;用结构化输出&#xff1a;如直接要求它以HTML或者JSON格式输出方法3&#xff1a;请模型检查是否满足条件方法4&#xff…

01-环境搭建 尚筹网

环境搭建 一、项目结构搭建 ​ 模块关系 ​ parent模块仅仅用来确定各个Maven依赖的版本 ​ webui、component、entity模块继承自parent模块 ​ util、reverse模块属于独立工程&#xff0c;不参与继承与聚合 ​ 且webui依赖于component&#xff0c;component依赖于entity…

Cont. TF-IDF (BigData Data Mining)

Cont. 举例 例1 词频 (TF) 是一词语出现的次数除以该文件的总词语数。 假如一篇文件的总词语数是100个&#xff0c;而词语“母牛”出现了3次&#xff0c;那么“母牛”一词在该文件中的词频就是3/1000.03。 一个计算文件频率 (IDF) 的方法是文件集里包含的文件总数除以测定有多…

一些关于单链表的操作

思维导图&#xff1a; 一&#xff0c; 链表 1.1节点的结构 链表是啥样的啊&#xff1f;顾名思义链表就是一种用链子链接起来的表。那这种表是怎么样的啊&#xff1f; 这样的呗&#xff1a; 现在&#xff0c;我们知道了链表的形状了。那我们该如何用编程语言来形成这一种形状…

mysql 安装全过程(linux上二进制包安装)

介绍 mysql 是一种RDBMS 关系型数据库管理系统 Relational Database Management System 关系型数据库将数据保存在不同的表中&#xff0c;而不是放在一个大仓库内&#xff0c;增加了速度&#xff0c;提高了灵活性。 . mysql版本 5.7.x 和 8.0.x 是目前主流。2个…

RT-Thread 在线软件包改为本地软件包的方法

问题描述 RT-Thread 的软件包&#xff0c;使用时&#xff0c;需要手动通过 ENV 工具 更新到 本地的 packages 目录&#xff0c;并且 packages 目录默认不参与 Git 工程管理&#xff0c;软件包多了&#xff0c;并且偶尔需要更改软件包本身的一些代码&#xff0c;这就造成了软件项…

Spring 依赖注入源码

文章目录 依赖注入原始依赖注入方式注解方式寻找注入点注入点进行注入 从BeanFactory中找注入对象总结 依赖注入 具体代码是在AbstractAutowireCapableBeanFactory类的populateBean()方法&#xff0c;此方法中主要做的事情如下&#xff1a; 实例化之后&#xff0c;调用Instan…

【Java校招面试】基础知识(二)——Spring Framework AOP

目录 前言一、Spring Framewwork基础知识二、Spring AOP基础概念1. 切面&#xff08;Aspect&#xff09;2. 织入&#xff08;Weaving&#xff09;3. 增强&#xff08;Advice&#xff09;4. 动态代理 三、JDK动态代理1. 基本用法2. 原理分析 四、CGLib动态代理1. 基本用法2. 原理…

【五一创作】使用Resnet残差网络对图像进行分类(猫十二分类,模型定义、训练、保存、预测)(二)

使用Resnet残差网络对图像进行分类 &#xff08;猫十二分类&#xff0c;模型定义、训练、保存、预测&#xff09;(二&#xff09; 目录 &#xff08;6&#xff09;、数据集划分 &#xff08;7&#xff09;、训练集增强 &#xff08;8&#xff09;、装载数据集 &#xff08…

山东专升本计算机第十一章-新一代信息技术

新一代信息技术 物联网 概念 物联网就是物物相连的互联网&#xff0c;其核心和基础仍然是互联网 计算机&#xff0c;互联网之后信息产业发展的第三次浪潮 推入人类进入智能时代&#xff0c;又称物联时代 三大特征 全面感知 可靠传递 智能处理 • 物联网的最核心 技术架…

阿里云g8i服务器ECS通用型服务器CPU处理器性能测评

阿里云服务器ECS通用型实例规格族g8i采用2.7 GHz主频的Intel Xeon(Sapphire Rapids) Platinum 8475B处理器&#xff0c;3.2 GHz睿频&#xff0c;g8i实例采用阿里云全新CIPU架构&#xff0c;可提供稳定的算力输出、更强劲的I/O引擎以及芯片级的安全加固。阿里云百科分享阿里云服…

JavaScript 入门(1)

script 标签 <scrtipt> 标签可以插入到HTML中的任何位置在很老的代码中需使用type属性&#xff0c;但是现在的代码中不需要 <script type"text/javascript"><!-- ... //--></script>外部脚本 通过src 属性将脚本添加到HTML中 <script …

Maven的全面讲解及如何安装使用

Maven是一种流行的Java项目管理工具&#xff0c;可用于构建、测试、打包和部署Java应用程序。本文将介绍Maven的概念、安装配置、使用方法、生命周期以及IDEA集成Maven的方法。 Maven的概念 Maven是一种基于项目对象模型&#xff08;POM&#xff09;的构建工具。POM是一个XML…

【C++】位运算类题目总结

文章目录 一. 位运算符脑图二. 相关题目1. 统计二进制数中0的个数2. 数组中只出现一次的数字3. 数组中只出现一次的数字 II4. 不用加减乘除做加法 一. 位运算符脑图 二. 相关题目 1. 统计二进制数中0的个数 解题思路&#xff1a;x & (x-1)&#xff1b;它的作用是每次循环…

系统集成项目管理工程师 笔记(第18章:项目风险管理)

文章目录 18.1.2 风险的分类 54318.1.3 风险的性质 544项目风险管理6个过程&#xff08;风险管理、识别风险、实施定性风险分析、实施定量风险分析、规划风险应对、控制风险&#xff09;组织和干系人的风险态度影响因素18.3.3 规划风险管理的输出 550风险识别的原则18.4.2 识别…

针对Vue前后端分离项目的渗透思路

引言 在目前的开发环境下&#xff0c;越来越多的厂商选择 Vue.js 来实现前端功能的编写&#xff0c;且成熟的前端框架已经可以实现后端代码实现的功能&#xff0c;导致后端目前只负责提供 Api 接口和文档&#xff0c;方便前端的同时去调用。本文主要介绍如何针对这类前后端分离…

如何利用几何坐标变换后纠正技术实现倾斜摄影三维模型数据拼接?

如何利用几何坐标变换后纠正技术实现倾斜摄影三维模型数据拼接&#xff1f; 倾斜摄影三维模型数据拼接是指将多个倾斜摄影数据集合并为一个完整的三维模型。在这个过程中&#xff0c;由于不同数据集之间的相对位置和姿态不同&#xff0c;需要进行几何坐标变换以实现数据拼接。…