设计模式之模板方法模式

概述

在面向对象程序设计过程中,程序员常常会遇到这种情况:设计一个系统时知道了算法所需的关键步骤,而且确定了这些步骤的执行顺序,但某些步骤的具体实现还未知,或者说某些步骤的实现与具体的环境相关。

例如,去银行办理业务一般要经过以下4个流程:取号、排队、办理具体业务、对银行工作人员进行评分等,其中取号、排队和对银行工作人员进行评分的业务对每个客户是一样的,可以在父类中实现,但是办理具体业务却因人而异,它可能是存款、取款或者转账等,可以延迟到子类中实现。

这样的例子在生活中还有很多,例如,一个人每天会起床、吃饭、做事、睡觉等,其中“做事”的内容每天可能不同。我们把这些规定了流程或格式的实例定义成模板,允许使用者根据自己的需求去更新它,例如,简历模板、论文模板、Word 中模板文件等。

以下介绍的模板方法模式将解决以上类似的问题。

模板方法(Template Method)模式的定义如下:定义一个操作中的算法骨架,而将算法的一些步骤延迟到子类中,使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤。它是一种类行为型模式。

结构

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

  • 抽象类(Abstract Class):负责给出一个算法的轮廓和骨架。它由一个模板方法和若干个基本方法构成。

    • 模板方法:定义了算法的骨架,按某种顺序调用其包含的基本方法。

    • 基本方法:是实现算法各个步骤的方法,是模板方法的组成部分。基本方法又可以分为三种:

      • 抽象方法(Abstract Method) :一个抽象方法由抽象类声明、由其具体子类实现。

      • 具体方法(Concrete Method) :一个具体方法由一个抽象类或具体类声明并实现,其子类可以进行覆盖也可以直接继承。

      • 钩子方法(Hook Method) :在抽象类中已经实现,包括用于判断的逻辑方法和需要子类重写的空方法两种。

        一般钩子方法是用于判断的逻辑方法,这类方法名一般为isXxx,返回值类型为boolean类型。

  • 具体子类(Concrete Class):实现抽象类中所定义的抽象方法和钩子方法,它们是一个顶级逻辑的组成步骤。

例:炒菜的步骤是固定的,分为倒油、热油、倒蔬菜、倒调料品、翻炒等步骤。现通过模板方法模式来用代码模拟。UML类图如下:

各代码实现类如下:

  • AbstractClass.java
public abstract class AbstractClass {// 定义唯一一个模板方法,定义了基本方法的执行流程,因为执行流程是固定的不应该被修改,所以使用final修饰public final void cookProcess() {pourOil();heatOil();pourVegetable();pourSauce();fry();}// 第一步,倒油public void pourOil() {System.out.println("倒油");}// 第二步,热油,直接实现该方法public void heatOil() {System.out.println("热油");}// 第三步,倒素菜,这是不一样的,一个是下包菜,一个是下菜心,需要用户自己实现,抽象方法public abstract void pourVegetable();// 第四步,倒调味料,这也是不一样的,抽象方法public abstract void pourSauce();// 第五步,翻炒public void fry() {System.out.println("翻炒至熟");}
}
  • ConcreteClass_BaoCai.java
public class ConcreteClass_BaoCai extends AbstractClass{@Overridepublic void pourVegetable() {System.out.println("下锅的蔬菜是包菜");}@Overridepublic void pourSauce() {System.out.println("下锅的佐料是青椒");}
}
  • ConcreteClass_CaiXin.java
public class ConcreteClass_CaiXin extends AbstractClass {@Overridepublic void pourVegetable() {System.out.println("下锅的蔬菜是菜心");}@Overridepublic void pourSauce() {System.out.println("下锅的佐料是蒜");}
}
  • Test.java
public class Test {public static void main(String[] args) {// 炒包菜ConcreteClass_BaoCai baoCai=new ConcreteClass_BaoCai();// 调用方法进行炒菜baoCai.cookProcess();}
}

其实类似的例子还很多,如工作上班,每天做的事情是上班打卡、工作或摸鱼、下班打卡。

注意:为防止恶意操作,一般模板方法都加上 final 关键词

优缺点

该模式的主要优点如下。

  1. 它封装了不变部分,扩展可变部分。它把认为是不变部分的算法封装到父类中实现,而把可变部分算法由子类继承实现,便于子类继续扩展。
  2. 它在父类中提取了公共的部分代码,便于代码复用。
  3. 部分方法是由子类实现的,因此子类可以通过扩展方式增加相应的功能,符合开闭原则。

该模式的主要缺点如下。

  1. 对每个不同的实现都需要定义一个子类,这会导致类的个数增加,系统更加庞大,设计也更加抽象,间接地增加了系统实现的复杂度。
  2. 父类中的抽象方法由子类实现,子类执行的结果会影响父类的结果,这导致一种反向的控制结构,它提高了代码阅读的难度。
  3. 由于继承关系自身的缺点,如果父类添加新的抽象方法,则所有子类都要改一遍。

适用场景:

  • 算法的整体步骤很固定,但其中个别部分易变时,这时候可以使用模板方法模式,将容易变的部分抽象出来,供子类实现。

  • 需要通过子类来决定父类算法中某个步骤是否执行,实现子类对父类的反向控制。

JDK源码解析

InputStream类就使用了模板方法模式。在InputStream类中定义了多个 read() 方法,如下:

public abstract class InputStream implements Closeable {//抽象方法,要求子类必须重写public abstract int read() throws IOException;public int read(byte b[]) throws IOException {return read(b, 0, b.length);}public int read(byte b[], int off, int len) throws IOException {if (b == null) {throw new NullPointerException();} else if (off < 0 || len < 0 || len > b.length - off) {throw new IndexOutOfBoundsException();} else if (len == 0) {return 0;}int c = read(); //调用了无参的read方法,该方法是每次读取一个字节数据if (c == -1) {return -1;}b[off] = (byte)c;int i = 1;try {for (; i < len ; i++) {c = read();if (c == -1) {break;}b[off + i] = (byte)c;}} catch (IOException ee) {}return i;}
}

从上面代码可以看到,无参的 read() 方法是抽象方法,要求子类必须实现。而 read(byte b[]) 方法调用了 read(byte b[], int off, int len) 方法,所以在此处重点看的方法是带三个参数的方法。

在该方法中可以看到调用了无参的抽象的 read() 方法。

总结如下: 在InputStream父类中已经定义好了读取一个字节数组数据的方法是每次读取一个字节,并将其存储到数组的第一个索引位置,读取len个字节数据。具体如何读取一个字节数据呢?由子类实现。

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

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

相关文章

matlab 滤波器设计工具,滤波器设计工具快速入门

滤波器设计工具快速入门 要打开滤波器设计工具,请键入 filterDesigner(在 MATLAB 命令提示符下键入。) 将打开滤波器设计工具并显示“设计滤波器”面板。 请注意,当您打开设计滤波器并未启用。您必须对默认滤波器设计进行更改以启用设计滤波器。每次您要更改滤波器设计时,均…

ChatGPT有用到知识图谱吗?| 文末送最新《知识图谱实战》书籍

文末留言点赞前五名送书&#xff0c;截止时间2023.4.2(本周日) 20:00 进NLP群—>加入NLP交流群(备注nips/emnlp/nlpcc进入对应投稿群) 从搜索引擎到个人助手&#xff0c;我们每天都在使用问答系统。问答系统必须能够访问相关的知识并进行推理。通常&#xff0c;知识可以隐式…

ChatGPT的诞生

这就是为什么ChatGPT 不可能在中国出现的原因 自欺欺人在家里玩可以&#xff0c;但是 你只是这世界的1/6而已&#xff0c;不可能 欺骗其他5/6的人类 最后还是自己傻比了

51 种 AI 工具,生活、编程、内容创建都应该使用它

AI 正在席卷全球 &#x1f525;&#x1f525;&#x1f525; 它具有无限的潜力&#xff0c;并将改变我们的生活&#xff0c;让生活变得更美好。这项技术将迅速改进&#xff0c;您今天可以使用许多工具来提高您的工作效率&#xff0c;帮助您完成工作&#xff0c;为您提供有关许多…

SpringBoot+Vue+Uniapp搭建的Java版本的ChatGPT智能Ai对话系统

chatgpt-java-system 介绍 SpringBootVueUniapp搭建的Java版本的ChatGPT智能Ai对话系统&#xff0c;小程序和H5包含智能Ai对话、精美Ai壁纸、知识付费商城、积分、会员、分享等公功能&#xff1b;后端管理包括系统管理、智能对话、基本设置、系统监控、代码生成、壁纸管理和商…

chatgpt赋能python:Python解决找零问题--极简演示

Python解决找零问题 – 极简演示 在日常生活中&#xff0c;我们经常需要进行找零计算。如果使用笔和纸来手动计算&#xff0c;则会浪费很多时间和精力。但是Python作为一种高级编程语言&#xff0c;可以轻松地解决这个问题&#xff0c;省去人工计算的烦恼。 什么是Python找零…

九龙证券|远离资本市场噪音的四种方法

我们都知道人是自我完成的群体&#xff0c;自我完成便是便是有方案有目的辅导自己的行为&#xff0c;目标或预期在很大程度上决定着人们的取得感&#xff0c;就好像以下公式所表现的相同&#xff1a;取得感所得/预期&#xff0c;那么股市中的预期是什么&#xff1f;怎么进行预期…

Redis漏洞导致ChatGPT重大故障,OpenAI公布技术细节

因公众号更改推送规则&#xff0c;请点“在看”并加“星标”第一时间获取精彩技术分享 点击关注#互联网架构师公众号&#xff0c;领取架构师全套资料 都在这里 0、2T架构师学习资料干货分 上一篇&#xff1a;ChatGPT研究框架&#xff08;80页PPT&#xff0c;附下载&#xff09;…

ChatGPT4 给出数据库开发者最容易犯的10个错误和解决方案

昨天 ChatGPT4 刚刚发布&#xff0c;迫不及待体验了一把。 ChatGPT 4 目前是付费使用&#xff0c;使用次数也有限制&#xff0c;门槛更高&#xff0c;API 调用费用是ChatGPT 3.5 的15倍&#xff0c;官网网站也经常登录不上。 我让 ChatGPT4 列举出【数据库开发者最容易犯的10个…

小白学习chatgpt

很明显&#xff0c;chatgpt的能力超出了人们过往对人工智能的认知&#xff0c;在使用过程中他的能力让我吃惊&#xff0c;而且具有通用性&#xff08;AGI&#xff09;&#xff0c;这一点在以往的人工智能中表现得比较少&#xff0c;具体在GPT-4的早期实验报告中有更多的说明。可…

解密Prompt系列8. 无需训练让LLM支持超长输入:知识库 unlimiformer PCW NBCE

这一章我们聊聊有哪些方案可以不用微调直接让大模型支持超长文本输入&#xff0c;注意这里主要针对无限输入场景。之前在BERT系列中我们就介绍过稀疏注意力和片段递归的一些长文本建模方案长文本建模 BigBird & Longformer & Reformer & Performer&#xff0c;不过…

3DTrans: 首个支持自动驾驶室外点云迁移学习的代码库

本文将为大家介绍上海人工智能实验室交通平台组ADLab的3DTrans代码库–首个自动驾驶室外3D点云迁移学习的代码库。此外3DTrans代码库还是Uni3D&#xff08;CVPR-2023&#xff09;和Bi3D&#xff08;CVPR-2023&#xff09;的官方实现代码库。 Code Link: https://github.com/PJ…

文心一言 VS chatgpt (21)-- h264编码一帧数据的流程是怎样的?

h264编码一帧数据的流程是怎样的&#xff1f; 文心一言&#xff1a; H.264编码将一帧数据分成多个块&#xff0c;其中每个块可以单独进行编码。编码的过程包括预测、变换和量化等步骤。 具体流程如下&#xff1a; 1.帧内预测&#xff1a;对一帧视频进行编码&#xff0c;首先…

chatgpt赋能python:用Python计算AIC:一种常用的信息标准

用Python计算AIC&#xff1a;一种常用的信息标准 介绍 AIC&#xff08;赤池信息准则&#xff09;是一种用于模型选择的信息理论标准&#xff0c;旨在平衡模型复杂度和拟合准确度的权衡。在统计学和机器学习中&#xff0c;模型选择是一项关键任务&#xff0c;因为正确选择模型…

chatgpt赋能python:Python中如何产生0到1包括1的随机数

Python中如何产生0到1包括1的随机数 Python作为一种高级编程语言&#xff0c;被广泛运用于各种程序开发领域&#xff0c;尤其得到了数据科学、数据分析和机器学习领域的青睐。在Python中&#xff0c;实现随机数的生成是很平凡的&#xff0c;下面我将会给大家介绍如何使用Pytho…

chatgpt赋能python:Python的UUID是什么?

Python的UUID是什么&#xff1f; Python的UUID是一种广泛使用的标识符生成器&#xff0c;全称是“通用唯一标识符”。UUID可以帮助你在使用Python编程时生成唯一的ID。无论你在哪个项目中使用Python&#xff0c;UUID都会非常有用。 使用Python编程的开发者一定会碰到需要生成…

股价狂跌超70%,特斯拉到底怎么了?

​在2022年的尾声&#xff0c;曾在新能源汽车领域盛极一时的特斯拉即将取得上市以来最糟糕的年度表现&#xff0c;直接跌出全球上公司市值前10名。目前特斯拉已连续第7个交易日下跌&#xff0c;截至2022年12月28日&#xff0c;跌超11%&#xff0c;创八个月最大跌幅&#xff0c;…

如何查询外文文献?

作为专业的科研人&#xff0c;不具备搜索外文文献的技能怎么能行呢&#xff1f;&#xff01;今天&#xff0c;我就为大家汇集了各类的外文文献下载途径&#xff0c;内容干货满满&#xff0c;还不快快收藏&#xff01;一、EBSCOhost 网址&#xff1a;http://search.ebscohost.co…

基于深度学习的人脸面部表情识别方法研究

开发工具(eclipse/idea/vscode等)&#xff1a;python tensorflow keras 数据库(sqlite/mysql/sqlserver等)&#xff1a; 功能模块(请用文字描述&#xff0c;至少200字)&#xff1a;以python为变成语言&#xff0c;使用pycharm进行开发。使用深度学习框架TensorFlow和keras。了准…

基于Python的人脸表情管理系统

人脸表情识别是深度学习领域的研究热点。在现实场景中&#xff0c;人脸图像的采集很容易受到外界不可控因素的影响&#xff0c;使表情图像出现轻微形变和局部位移的问题&#xff0c;导致表情识别率下降&#xff0c;难以满足实际需求。因此本设计针对静态人脸表情进行识别分类&a…