模版方法模式详解:使用和实现的指南

目录

  • 模版方法模式
    • 模版方法模式结构
    • 模版方法模式适合应用场景
    • 模版方法模式优缺点
    • 练手题目
      • 题目描述
      • 输入描述
      • 输出描述
      • 题解

模版方法模式

模板方法模式是一种行为设计模式, 它在超类中定义了一个算法的框架, 允许子类在不修改结构的情况下重写算法的特定步骤。

类比真实世界中建造大量房屋。 标准房屋建造方案中可提供几个扩展点, 允许潜在房屋业主调整成品房屋的部分细节。

每个建造步骤 (例如打地基、 建造框架、 建造墙壁和安装水电管线等) 都能进行微调, 这使得成品房屋会略有不同。

在这里插入图片描述

模版方法模式结构

在这里插入图片描述

  1. 抽象类 (Abstract­Class) 会声明作为算法步骤的方法, 以及依次调用它们的实际模板方法。 算法步骤可以被声明为 抽象类型, 也可以提供一些默认实现。

  2. 具体类 (Concrete­Class) 可以重写所有步骤, 但不能重写模板方法自身。

一般,模版方法都加上final关键字,不允许被覆写。

通用代码结构

//抽象类定义了一个模板方法,其中通常会包含某个由抽象原语操作调用组成的算法框架。
public abstract class AbstractClass{//基本算法步骤protected abstract void step1();protected abstract void step2();//模版方法final public void templateMethod(){//算法基本逻辑this.step1();this.step2();...}
}// 具体类必须实现基类中的所有抽象操作,但是它们不能重写模板方法自身。
public class ConcreteClass1 extends AbstractClass{//实现基本方法protected abstract void step1(){...};protected abstract void step2(){....};
}public class ConcreteClass2 extends AbstractClass{//实现基本方法protected abstract void step1(){...};protected abstract void step2(){....};
}//客户端
public class Client{public static void main(String[] args){AbstractClass class1 = new ConcreteClass1();AbstractClass class2 = new ConcreteClass2();class1.templateMethod();class2.templateMethod();}
}

模版方法模式适合应用场景

  • 当你只希望客户端扩展某个特定算法步骤,而不是整个算法或其结构时,可使用模板方法模式。

  • 当多个类的算法除一些细微不同之外几乎完全一样时,你可使用该模式。但其后果就是,只要算法发生变化,你就可能需要修改所有的类。

在这里插入图片描述

**识别方法:**模版方法可以通过行为方法来识别,该方法已有一个在基类中定义的 “默认” 行为。

模版方法模式优缺点

模版方法模式的优点

  • 你可仅允许客户端重写一个大型算法中的特定部分, 使得算法其他部分修改对其所造成的影响减小。

  • 你可将重复代码提取到一个超类中。

模版方法模式的缺点

  • 部分客户端可能会受到算法框架的限制。

  • 通过子类抑制默认步骤实现可能会导致违反里氏替换原则

  • 模板方法中的步骤越多, 其维护工作就可能会越困难。

练手题目

题目描述

小明喜欢品尝不同类型的咖啡,她发现每种咖啡的制作过程有一些相同的步骤,他决定设计一个简单的咖啡制作系统,使用模板方法模式定义咖啡的制作过程。系统支持两种咖啡类型:美式咖啡(American Coffee)和拿铁(Latte)。

咖啡制作过程包括以下步骤:

  1. 研磨咖啡豆 Grinding coffee beans

  2. 冲泡咖啡 Brewing coffee

  3. 添加调料 Adding condiments

其中,美式咖啡和拿铁的调料添加方式略有不同, 拿铁在添加调料时需要添加牛奶Adding milk

输入描述

多行输入,每行包含一个数字,表示咖啡的选择(1 表示美式咖啡,2 表示拿铁)。

输出描述

根据每行输入,输出制作咖啡的过程,包括咖啡类型和各个制作步骤,末尾有一个空行。

在这里插入图片描述

题解

模版方法实现。

import java.util.Scanner;// 抽象类,定义咖啡制作的基本步骤
abstract class CoffeeModel {private String coffeeName;// 构造函数,接受咖啡名称参数public CoffeeModel(String coffeeName) {this.coffeeName = coffeeName;}protected abstract void grind();protected abstract void brew();protected abstract void addCondiments();// 添加其他调料可使用该类public void addThings(){};// 模板方法,定义咖啡制作的流程public final void createCoffeeTemplate() {System.out.println("Making " + coffeeName + ":");grind();brew();//根据情况,是否调用添加更多调料if (isAddThings()) {addThings(); }addCondiments();System.out.println();}// 默认不添加其他调料。如牛奶等public boolean isAddThings() {return false;}
}//美式咖啡类实现
class CreateAmericanCoffee extends CoffeeModel {public CreateAmericanCoffee() {super("American Coffee");}@Overrideprotected void grind() {System.out.println("Grinding coffee beans");}@Overrideprotected void brew() {System.out.println("Brewing coffee");}@Overrideprotected void addCondiments() {System.out.println("Adding condiments");}// 美式咖啡默认不添加其他调料,如牛奶等@Overridepublic boolean isAddThings() {return false; }
}//拿铁类实现
class CreateLatte extends CoffeeModel {private boolean addThingsFlag = true;public CreateLatte() {super("Latte");}@Overrideprotected void grind() {System.out.println("Grinding coffee beans");}@Overrideprotected void brew() {System.out.println("Brewing coffee");}@Overrideprotected void addCondiments() {System.out.println("Adding condiments");}//需要添加调料,牛奶@Overridepublic void addThings(){System.out.println("Adding milk");}// 拿铁默认添加牛奶@Overridepublic boolean isAddThings() {return this.addThingsFlag; }// 外部调用以改变是否添加牛奶的状态,钩子函数public void setAddThingsFlag(boolean flag) {this.addThingsFlag = flag;}
}public class Main {public static void main(String[] args) {try (Scanner scanner = new Scanner(System.in)) {while (scanner.hasNextInt()) {int input = scanner.nextInt();CoffeeModel coffee;switch (input) {case 1:coffee = new CreateAmericanCoffee();break;case 2:coffee = new CreateLatte();break;default:System.out.println("无效选择,请输入1或2");continue;}coffee.createCoffeeTemplate();}}}
}

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

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

相关文章

《昇思25天学习打卡营第3天|张量 Tensor》

文章目录 前言:今日所学:1. 创建张量2. 张量的属性3.张量索引与运算4. NumPy与Tensor的转换5. 稀疏张量 前言: 张量?张亮?张量是什么? 张量是一个可以用来表示在一些矢量、标量和其他张量之间的线性关系的…

leetcode 第133场双周赛 100333.统计逆序对的数目【计数dp/滚动数组/前缀和优化】

分析: 先考虑如下问题。 求长度为n,逆序对为m的排列数量。 可以考虑dp,dp[i][j]定义为长度为i,逆序对为j的排列数量。 dp[1][0] 1; //枚举排列长度,或者认为枚举当前需要插到长度为i-1的排列中的数字 for(int i 1…

OpenAI封杀不支持地区API:违规封号,7月9日生效

OpenAI 在检测用户使用其 API 的地区后,提示所有不支持位置的用户 昨晚,很多大模型应用的开发者、程序员都收到了 OpenAI 的警告信,心里一惊。 OpenAI 在检测用户使用其 API 的地区后,提示所有不支持位置的用户:即将封…

图书管理系统(附源码)

前言:前面一起和小伙伴们学习了较为完整的Java语法体系,那么本篇将运用这些知识连串在一起实现图书管理系统。 目录 一、总体设计 二、书籍与书架 书籍(Book) 书架(Booklist) 三、对图书的相关操作 I…

已解决问题 | 该扩展程序未列在 Chrome 网上应用店中,并可能是在您不知情的情况下添加的

在Chrome浏览器中,如果你看到“该扩展程序未列在 Chrome 网上应用店中,并可能是在您不知情的情况下添加的”这样的提示,通常是因为该扩展程序没有通过Chrome网上应用店进行安装。以下是解决这个问题的步骤: 解决办法:…

kali/ubuntu安装vulhub

无须更换源,安装docker-compose apt install docker.io docker -vdocker-compose #提示没有,输入y安装mkdir -p /etc/docker vi /etc/docker/daemon.json #更换dockerhub国内源┌──(root㉿kali)-[/home/kali/vulhub-master/tomcat/CVE-2017-12615] …

dledger原理源码分析系列(三)-选主

简介 dledger是openmessaging的一个组件, raft算法实现,用于分布式日志,本系列分析dledger如何实现raft概念,以及dledger在rocketmq的应用 本系列使用dledger v0.40 本文分析dledger的选主 关键词 Raft Openmessaging 心跳/选…

Linux安装redis教程(超级详细,新手必看)

环境: Centos 7.9 一、安装准备工作 1.配置gcc 安装redis前需要配置gcc: yum install gcc如果配置gcc出现依赖包问题,可以到主页查看帖子解决:https://blog.csdn.net/m0_59117906/article/details/134451622?spm1001.2014.300…

这四款软件很好用,可以提升工作、学习效率

TableConvert TableConvert是一个基于Web的在线表格转换工具,能够将多种格式的表格数据进行快速转换。它支持将Excel、URL、HTML、JSON、CSV等格式转换为Markdown表、CSV/TSV、XML、YAML、插入SQL、HTML、Excel和LaTeX等格式。用户只需将表格数据粘贴到编辑器&#…

本教程将指导如何通过 Vue 组件和后端 API 交互

本人详解 作者:王文峰,参加过 CSDN 2020年度博客之星,《Java王大师王天师》 公众号:JAVA开发王大师,专注于天道酬勤的 Java 开发问题中国国学、传统文化和代码爱好者的程序人生,期待你的关注和支持!本人外号:神秘小峯 山峯 转载说明:务必注明来源(注明:作者:王文峰…

CJSON库

目录 一、介绍 1、JSON是什么 2、为什么使用CJSON 3、JSON格式 二、使用CJSON构造JSON 1、创建对象 2、添加字段 3、转换格式 4、释放对象 三、使用CJSON解析JSON 1、解析数据 2、 获取字段 3、释放对象 一、介绍 1、JSON是什么 JSON是什么呢?JSON全称…

折半查找详解

一:折半查找概念 折半查找(也称为二分查找)是一种在有序数组中查找某一特定元素的搜索算法。搜索过程从数组的中间元素开始,如果中间元素正好是目标值,则搜索过程结束;如果目标值大于或小于中间元素&#x…

SSM网上旅游信息管理系统-计算机毕业设计源码06975

目 录 摘要 1 绪论 1.1 研究背景 1.2 研究意义 1.3论文结构与章节安排 2 系统分析 2.1 可行性分析 2.2 系统流程分析 2.2.1 数据新增流程 2.2.2 数据删除流程 2.3 系统功能分析 2.3.1 功能性分析 2.3.2 非功能性分析 2.4 系统用例分析 2.5本章小结 3 系统总体设…

微信小程序毕业设计-垃圾分类系统项目开发实战(附源码+论文)

大家好!我是程序猿老A,感谢您阅读本文,欢迎一键三连哦。 💞当前专栏:微信小程序毕业设计 精彩专栏推荐👇🏻👇🏻👇🏻 🎀 Python毕业设计…

Mathematica训练课(46)-- 一些常用的画图函数

在前面的课程中,我们已经梳理了Plot的画图用法,今天就详细梳理一下其他的画图函数用法; 1. 画一条直线 2. Circle(圆) 3. Disk(圆盘) 4. 画出一个矩形 5. 箭头

大数据可视化实验(六)——ECharts与pyecharts数据可视化

目录 一、实验目的... 1 二、实验环境... 1 三、实验内容... 1 1、ECharts可视化制作.. 1 1)使用ECharts绘制折线图显示一周的天气变换。... 1 2)使用ECharts绘制柱状图显示商品销量的变化。... 4 2、pyecharts可视化制作.. 7 1)使用…

【知识学习】Unity3D中Shader Graph的概念及使用方法示例

Unity3D中的Shader Graph是一个强大的可视化Shader编辑工具,它允许用户通过拖拽和连接节点的方式来创建Shader,而不是通过传统的编写代码的方式。Shader Graph使得Shader的创建过程更加直观和易于理解,特别是对于那些不熟悉Shader语言编程的美…

【OpenREALM学习笔记:13】pose_estimation.cpp和pose_estimation.h

UML Class Diagram 图中红色框为头文件中所涉及到的函数、变量和结构体 核心函数 PoseEstimation::process() 其核心作用为执行位姿估计的处理流程,并返回是否在此循环中进行了任何处理。 在这个函数中判断并完成地理坐标的初始化或这地理坐标的更新。 这里需要…

QTreeView第一列自适应

通过setStretchLastSection(bool stretch)可以设置最后一列自适应,对于QTreeView,stretch默认为true。但有时候我们需要设置第一列自适应,比如文件浏览器,共有名称、大小和修改日期三列,大小和日期的宽度几乎是固定的,但名称却可长可短,此时我们希望在窗口大小变化时,第…

IDEA中Maven配置依赖和排除依赖

目录 依赖配置 添加依赖的几种方式: 1.利用中央仓库搜索的依赖坐标 2.利用IDEA工具搜索依赖 3.熟练上手maven后,快速导入依赖 排除依赖 依赖配置 依赖:指当前项目运行所需要的jar包。一个项目中可以引入多个依赖: 例如&am…