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

devtools/2024/9/23 18:11:55/

目录

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

模版方法模式

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

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

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

在这里插入图片描述

模版方法模式结构

在这里插入图片描述

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

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

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

通用代码结构

java">//抽象类定义了一个模板方法,其中通常会包含某个由抽象原语操作调用组成的算法框架。
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 表示拿铁)。

输出描述

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

在这里插入图片描述

题解

模版方法实现。

java">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.ppmy.cn/devtools/56551.html

相关文章

Vite: 高阶特性 Pure ESM

概述 ESM 已经逐步得到各大浏览器厂商以及 Node.js 的原生支持,正在成为主流前端模块化方案。 而 Vite 本身就是借助浏览器原生的 ESM 解析能力( type“module” )实现了开发阶段的 no-bundle ,即不用打包也可以构建 Web 应用。不过我们对于原生 ESM 的…

Java对象创建过程

在日常开发中,我们常常需要创建对象,那么通过new关键字创建对象的执行中涉及到哪些流程呢?本文主要围绕这个问题来展开。 类的加载 创建对象时我们常常使用new关键字。如下 ObjectA o new ObjectA();对虚拟机来讲首先需要判断ObjectA类的…

【第9章】MyBatis-Plus持久层接口之SimpleQuery

文章目录 前言一、使用步骤1.引入 SimpleQuery 工具类2.使用 SimpleQuery 进行查询 二、使用提示三、功能详解1. keyMap1.1 方法签名1.2 参数说明1.3 使用示例1.4 使用提示 2. map2.1 方法签名2.2 参数说明2.3 使用示例2.4 使用提示 3. group3.1 方法签名3.2 参数说明3.3 使用示…

等保测评初级简答题试题

基本要求,在应用安全层面的访问控制要求中,三级系统较二级系统增加的措施有哪些? 答:三级比二级增加的要求项有: 应提供对重要信息资源设置敏感标记的功能; 应按照安全策略严格控制用户对有敏感标记重要…

【Java面试场景题】如何优化系统架构设计来缓解流量压力提升并发性能?

一、问题解析 我会以直播互动为例,带你看看读多写多的情况下如何应对流量压力。- 一般来说,这种服务多数属于实时互动服务,因为时效性要求很高,导致很多场景下,我们无法用读缓存的方式来降低核心数据的压力。所以&…

【C++】this指针

this指针 this指针指向被调用的成员函数所属的对象 this指针的用途: 当形参和成员变量同名时,可用this指针来区分 class animal{ pubilc:animal(int age){//把传进来的age赋值给成员变量agethis->age age;//this->age指成员变量ag…

uniapp, ‍[⁠TypeError⁠]‍ “Failed to fetch dynamically imported module“ 报错解决思路

文章目录 1. 背景2. 报错3. 解决思路4. 思考参考1. 背景 最近基于uniapp开发一款设备参数调试的APP软件,在使用第三方插件的过程中,出现下面的报错。 2. 报错 [plugin:vite:import-analysis] Cannot find module ‘D:/leaning/uniapp/demo/jk-uts-udp示例/uni_modules/uts-…

【Python游戏】猫和老鼠

本文收录于 《一起学Python趣味编程》专栏,从零基础开始,分享一些Python编程知识,欢迎关注,谢谢! 文章目录 一、前言二、代码示例三、知识点梳理四、总结一、前言 本文介绍如何使用Python的海龟画图工具turtle,开发猫和老鼠游戏。 什么是Python? Python是由荷兰人吉多范…