<设计模式修炼>模板方法模式的使用场景和注意事项学习

介绍

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

场景

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

  1. 制作豆浆的流程 选材—>添加配料—>浸泡—>放到豆浆机打碎
  2. 通过添加不同的配料,可以制作出不同口味的豆浆
  3. 选材、浸泡和放到豆浆机打碎这几个步骤对于制作每种口味的豆浆都是一样的
  4. 请使用 模板方法模式 完成 (说明:因为模板方法模式,比较简单,很容易就想到这个方案,因此就直接使用,不再使用传统的方案来引出模板方法模式 )

代码演示:

1.定义抽象类,提供抽象方法
SoyaMilk是抽象类,make是制作豆浆的抽象方法,只需要根据放入原料的不同就可以制造不同口味的豆浆,所以添加原料是一个抽象方法,交给子类去实现,调用的时候通过不同的子类对象就可以制作不同口味的豆浆
public abstract class SoyaMilk {

final void make(){select();addCondiments();soak();bead();}void select(){System.out.println("1.选择新鲜黄豆");
}abstract void addCondiments();void soak(){System.out.println("3.开始浸泡");
}void bead(){System.out.println("4.黄豆和配料放在豆浆机打碎");
}

}
2.提供子类重写抽象方法
制作花生豆浆子类:

public class PeanutSoyaMilk extends SoyaMilk {@Overridevoid addCondiments() {System.out.println("2.添加花生原料");}
}

制作红豆豆浆子类:

public class RedBeanSoyaMilk  extends  SoyaMilk{@Overridevoid addCondiments() {System.out.println("2.添加红豆配料");}
}

3.方法测试

public class TemplateTest {public static void main(String[] args) {SoyaMilk peanutSoyaMilk = new PeanutSoyaMilk();SoyaMilk redBeanSoyaMilk = new RedBeanSoyaMilk();peanutSoyaMilk.make();redBeanSoyaMilk.make();}
}

运行结果:

钩子方法

1.在模板方法模式的父类中,我们可以定义一个方法,它默认不做任何事,子类可以视情况要不要覆盖它,该方法称为“钩子”。
2.还是用上面做豆浆的例子来讲解,比如,我们还希望制作纯豆浆,不添加任何的配料,请使用钩子方法对前面的模板方法进行改造
抽象方法改造,提供空实现

    void addCondiments(){};

制作原味豆浆实现类

public class OriginalMilk extends SoyaMilk{@Overridevoid addCondiments() {super.addCondiments();}
}

子类视情况而定是否要覆盖父类方法。

框架源码体现

在Spring源码中,就使用到了模板方法模式,就在容器刷新的方法中
ConfigurableApplicationContext接口中定义了一个抽象方法refresh

在其实现类AbstractApplicationContext中实现了这个模板方法
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();

		// Tell the subclass to refresh the internal bean factory.ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();// Prepare the bean factory for use in this context.prepareBeanFactory(beanFactory);try {// Allows post-processing of the bean factory in context subclasses.postProcessBeanFactory(beanFactory);// Invoke factory processors registered as beans in the context.invokeBeanFactoryPostProcessors(beanFactory);// Register bean processors that intercept bean creation.registerBeanPostProcessors(beanFactory);// Initialize message source for this context.initMessageSource();// Initialize event multicaster for this context.initApplicationEventMulticaster();// Initialize other special beans in specific context subclasses.onRefresh();// Check for listener beans and register them.registerListeners();// Instantiate all remaining (non-lazy-init) singletons.finishBeanFactoryInitialization(beanFactory);// Last step: publish corresponding event.finishRefresh();}catch (BeansException ex) {if (logger.isWarnEnabled()) {logger.warn("Exception encountered during context initialization - " +"cancelling refresh attempt: " + ex);}// Destroy already created singletons to avoid dangling resources.destroyBeans();// Reset 'active' flag.cancelRefresh(ex);// Propagate exception to caller.throw ex;}finally {// Reset common introspection caches in Spring's core, since we// might not ever need metadata for singleton beans anymore...resetCommonCaches();}}
}

这个方法是Spring最重要的容器刷新的方法,我们看看在refresh方法中Spring通过模板方法模式留下了多少扩展点
1.obtainFreshBeanFactory()方法

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {refreshBeanFactory();return getBeanFactory();}

在obtainFreshBeanFactory的方法中refreshBeanFactory()和getBeanFactory()都是抽象方法,只能子类去实现,主要是为了初始化Spring容器并获取子类创建的BeanFactoy
2.postProcessBeanFactory(beanFactory)方法

	protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {}

它是一个钩子方法,交给子类去实现
3.onRefresh()方法

	protected void onRefresh() throws BeansException {// For subclasses: do nothing by default.}

它是一个钩子方法,交给子类去实现

注意事项和细节

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

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

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

相关文章

Proxy 与 defineProperty 的理解、区别、优势、劣势

一、Object.defineProperty() 文档:Object.defineProperty() - JavaScript | MDN 作用:对一个对象进行操作的方法。可以为一个对象增加一个属性,同时也可以对一个属性进行修改和删除。 它是在 ES5 中引入的,使用了 getter 和 s…

P10 RV1126推流项目——ffmpeg输出参数初始化

前言 从本章开始我们将要学习嵌入式音视频的学习了 ,使用的瑞芯微的开发板 🎬 个人主页:ChenPi 🐻推荐专栏1: 《C_ChenPi的博客-CSDN博客》✨✨✨ 🔥 推荐专栏2: 《Linux C应用编程(概念类)_C…

1.3 金融数据可视化

跳转到根目录:知行合一:投资篇 已完成: 1.1 编程基础   1.1.1 投资-编程基础-numpy   1.1.2 投资-编程基础-pandas 1.2 金融数据处理 1.3 金融数据可视化 文章目录 1. 金融数据可视化1.1. matplotlib1.1.1. 沪深300走势图1.1.2. 日线均线…

C++算法学习五.二叉树(1)

1.二叉树理论基础 二叉树的种类: 满二叉树:一棵二叉树只有度为0的结点和度为2的结点,并且度为0的结点在同一层上,则这棵二叉树为满二叉树。深度为k,总共有2的k次幂-1个节点。 完全二叉树:在完全二叉树中…

LeetCode 27.移除元素

移除元素 给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。 不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。 元素的顺序可以改变。你不需要考虑数组中超出新…

公司新招了个字节拿36K的人,让我见识到了什么才是测试扛把子......

5年测试,应该是能达到资深测试的水准,即不仅能熟练地开发业务,而且还能熟悉项目开发,测试,调试和发布的流程,而且还应该能全面掌握数据库等方面的技能,如果技能再高些的话,甚至熟悉分…

[Javaweb/LayUI/上机考试作业/开源]学生/图书/课程/仓库等管理系统六合一基础功能通用模板

展示 考试要求 给定用户表和六张图书/教师/顾客/仓库....的表(随机给每人抽选),要求实现用户登录注册,异步更新,对物品增删改查,精确/模糊查询等。 环境 tomcat 9 mysql 8 java 17 项目结构 项目类图 写前…

Java amr格式转mp3格式

1.问题描述 微信返回的语音是amr格式的,浏览器不能直接使用,所以需要转为mp3 注意:不能直接使用IO流转为mp3,不然H5还是用不了。转换之后的语音只能在播放器上播放,内里的文件格式其实还是amr 2.使用以下方式转换 音…

自制c++题目《抽象类与虚函数》

1.题目要求:构建一个抽象类car,由两个基类track和bike 继承,而它们共同的继承者是people类,要求构建上述类并撰写可辨别的语句 2.题解《抽象类与虚函数》的答案 王赫辰/c语言 - Gitee.com

tmux用法

tmux 安装 tmux sudo apt install tmux 运行 tmux tmux 退出 tmux exit 分离 tmux ctrl b, d 查看 tmux tmux ls 恢复 tmux tmux at -t <ID> 配置 tmux 在 ~/ 下面建一个 .tmux.conf 文件 set -g history-limit 9999 # 设置历史缓存长度 查看历史输出 …

Python学习笔记(五)函数、异常处理

目录 函数 函数的参数与传递方式 异常处理 函数 函数是将代码封装起来&#xff0c;实现代码复用的目的 函数的命名规则——同变量命名规则&#xff1a; 不能中文、数字不能开头、不能使用空格、不能使用关键字 #最简单的定义函数 user_list[] def fun(): #定义一个函数&…

Python正则表达式急速入门~正则居然这么容易掌握!

正则表达式在程序开发中会经常用到&#xff0c;比如数据&#xff08;格式&#xff09;验证、替换字符内容以及提取字符串内容等等情况都会用到&#xff0c;但是目前许多开发人员对于正则表达式只是处于了解或者是基本会用的阶段。一旦遇到大批量使用正则表达式的情况&#xff0…

Python初探:从零开始的编程奇妙之旅

一、Python是什么 Python是一门多用途的高级编程语言&#xff0c;以其简洁、易读的语法而脱颖而出。在深度学习领域&#xff0c;Python扮演着至关重要的角色。其丰富的科学计算库&#xff08;如NumPy、Pandas、Matplotlib&#xff09;和强大的深度学习框架&#xff08;如Tenso…

xshell设置终端类型为xterm-256color (解决oh-my-tmux颜色失真问题)

文章目录 问题描述解法效果检验 问题描述 在xshell远程连接服务器时&#xff0c;tmux色彩有问题&#xff08;tmux配置为Oh my tmux&#xff09;&#xff0c;如下&#xff1a; 这色彩明显是8位的色彩。 现在终端的标配就是类型为 xterm-256color&#xff0c;其支持256位的真彩…

CSU计算机学院2021年C语言期末题目思路分享(后两道题)

文章目录 E: 实数相加——大数加法的拓展原题题目描述输入输出样例输入样例输出 题目思路实现步骤代码和注释 F: 谍影寻踪——链表的思想和运用原题题目描述输入输出样例输入样例输出 题目思路 一点感想 E: 实数相加——大数加法的拓展 原题 题目描述 C语言就要期末考试了&a…

【操作系统习题】存储器与虚拟存储器

存储器 一、单选题 每次分配时总是从低地址到高地址顺序查找空闲区表&#xff0c;找到第一个能满足作业长度要求的空闲区&#xff0c;此种分配算法称为&#xff08;&#xff09; D A、最坏适应分配算法 B、随机适应分配算法 C、最优适应分配算法 D、首次适应分配算法一台计算…

深入探究:使用大型AI模型的实战指南

&#x1f482; 个人网站:【 海拥】【神级代码资源网站】【办公神器】&#x1f91f; 基于Web端打造的&#xff1a;&#x1f449;轻量化工具创作平台&#x1f485; 想寻找共同学习交流的小伙伴&#xff0c;请点击【全栈技术交流群】 在今天的技术领域&#xff0c;大型AI模型已成为…

2下载Spring,第一个Spring程序+引用Log4j2

https://www.yuque.com/dujubin/ltckqu/kipzgd#&#xff0c;注意的是&#xff0c;现在&#xff08;202401&#xff09;SpringFramework从release搬到了snapshot下&#xff0c;在这下面找到6.0.2下载. 下载后解压到文件夹&#xff0c;整个框架包含非常多jar包。 然后就可以在p…

C++:类和对象(2)

目录 1.strcut和class的区别 2.将成员属性设置为私有 3.对象的初始化和清理 3.1 构造函数和析构函数 3.1.1 构造函数语法 3.1.2 析构函数语法 3.1.3 检验 3.2 构造函数的分类和调用 3.3 拷贝构造函数调用 1.strcut和class的区别 struct和class的唯一区别在于默认的访问…

3个.NET开源简单易用的任务调度框架

前言 今天分享3个.NET开源、简单、易用的任务调度框架&#xff0c;帮助大家在做定时任务调度框架技术选型的时候有一个参考。 Quartz.Net Quartz.NET是一个功能齐全的开源作业调度系统&#xff0c;可用于从最小的应用程序到大规模企业系统。 Quartz.NetUI Quartz.NetUI是一…