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

news2025/1/15 6:21:04

目录

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

模版方法模式

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

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

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

在这里插入图片描述

模版方法模式结构

在这里插入图片描述

  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");
    }

    @Override
    protected void grind() {
        System.out.println("Grinding coffee beans");
    }

    @Override
    protected void brew() {
        System.out.println("Brewing coffee");
    }

    @Override
    protected void addCondiments() {
        System.out.println("Adding condiments");
    }
    
    // 美式咖啡默认不添加其他调料,如牛奶等
    @Override
    public boolean isAddThings() {
        return false; 
    }
}

//拿铁类实现
class CreateLatte extends CoffeeModel {
    private boolean addThingsFlag = true;

    public CreateLatte() {
        super("Latte");
    }

    @Override
    protected void grind() {
        System.out.println("Grinding coffee beans");
    }

    @Override
    protected void brew() {
        System.out.println("Brewing coffee");
    }

    @Override
    protected void addCondiments() {
        System.out.println("Adding condiments");
    }
    
    //需要添加调料,牛奶
    @Override
    public void addThings(){
        System.out.println("Adding milk");
    }
    
    // 拿铁默认添加牛奶
    @Override
    public 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.coloradmin.cn/o/1878978.html

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

相关文章

游戏推荐: 植物大战僵尸杂交版

下载地址网上一搜就有. 安装就能玩. 2是显血. 4显示植物血, 5是加速. 都是左手主键盘的按钮, 再按是取消. 比较刺激: ps: 设置里面还能打开自动收集阳光和金币.

Elasticsearch (1):ES基本概念和原理简单介绍

Elasticsearch(简称 ES)是一款基于 Apache Lucene 的分布式搜索和分析引擎。随着业务的发展,系统中的数据量不断增长,传统的关系型数据库在处理大量模糊查询时效率低下。因此,ES 作为一种高效、灵活和可扩展的全文检索…

斜率优化DP——AcWing 303. 运输小猫

斜率优化DP 定义 斜率优化DP(Slope Optimization Dynamic Programming)是一种高级动态规划技巧,用于优化具有特定形式的状态转移方程。它主要应用于那些状态转移涉及求极值(如最小值或最大值)的问题中,通…

加密与安全_三种方式实现基于国密非对称加密算法的加解密和签名验签

文章目录 国际算法基础概念常见的加密算法及分类签名和验签基础概念常见的签名算法应用场景 国密算法对称加密(DES/AES⇒SM4)非对称加密(RSA/ECC⇒SM2)散列(摘要/哈希)算法(MD5/SHA⇒SM3) Code方式一 使用B…

每日算法-插值查找

1.概念 插值查找是一种改良版的二分查找,其优势在于,对于较为均匀分布的有序数列,能够更快地使得mid中间游标快速接近目标值. 2.计算公式 中间游标计算公式. 公式说明: 公式的主要思路是,以第一次定位mid中间游标为例, 在接近平均分配的情况下,左右游标之间的差值表示总计供…

Linux线程同步【拿命推荐版】

目录 🚩引言 🚩听故事,引概念 🚩生产者消费者模型 🚀再次理解生产消费模型 🚀挖掘特点 🚩条件变量 🚀条件变量常用接口 🚀条件变量的原理 🚩引言 上一篇…

新的特性使得数据处理更加直观本教程将带你逐步了解如何使用Java Stream API

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

暑假集中备考2024年汉字小达人:来做18道历年选择题备考吧

结合最近几年的活动安排,预计2024年第11届汉字小达人比赛还有4个多月就启动,那么孩子们如何利用这段时间有条不紊地准备汉字小达人比赛呢? 我的建议是充分利用即将到来的暑假:①把小学1-5年级的语文课本上的知识点熟悉&#xff0…

[数据集][目标检测]围栏破损检测数据集VOC+YOLO格式1196张1类别

数据集格式:Pascal VOC格式YOLO格式(不包含分割路径的txt文件,仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数):1196 标注数量(xml文件个数):1196 标注数量(txt文件个数):1196 标注…

一篇就够了,为你答疑解惑:锂电池一阶模型-离线参数辨识(附代码)

锂电池一阶模型-参数离线辨识 背景模型简介数据收集1. 最大可用容量实验2. 开路电压实验3. 混合动力脉冲特性实验离线辨识对应模型对应代码总结下期预告文章字数有点多,耐心不够的谨慎点击阅读。 下期继续讲解在线参数辨识方法。 背景 最近又在开始重新梳理锂电池建模仿真与S…

Spring底层原理之bean的加载方式八 BeanDefinitionRegistryPostProcessor注解

BeanDefinitionRegistryPostProcessor注解 这种方式和第七种比较像 要实现两个方法 第一个方法是实现工厂 第二个方法叫后处理bean注册 package com.bigdata1421.bean;import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.…

wordpress企业主题和wordpress免费主题

农业畜牧养殖wordpress主题 简洁大气的农业畜牧养殖wordpress主题,农业农村现代化,离不开新农人、新技术。 https://www.jianzhanpress.com/?p3051 SEO优化wordpress主题 简洁的SEO优化wordpress主题,效果好不好,结果会告诉你…

天气网站爬虫及可视化

摘要:随着互联网的快速发展,人们对天气信息的需求也越来越高。本论文基于Python语言,设计并实现了一个天气网站爬虫及可视化系统。该系统通过网络爬虫技术从多个天气网站上获取实时的天气数据,并将数据进行清洗和存储。同时&#…

Halcon 椭圆

一 椭圆 方差的概念: 例1 两人的5次测验成绩如下:X: 50,100,100,60,50 E(X)72;Y: 73, 70, 75,72,70 E(Y)72。平均成绩相同&#xff0c…

idea 用久了代码提示变慢卡顿优化

idea 用久了代码提示变慢卡顿优化 修改虚拟机配置 修改编译构建堆内存

【proteus经典实战】16X192点阵程序

一、简介 6X192点阵程序通常用于表示高分辨率图像或文字,其中16X表示像素阵列的宽度,192表示每个像素阵列中的点阵数,16X192点阵程序需要一定的编程知识和技能才能编写和调试,同时还需要考虑硬件设备的兼容性和性能等因素。 初始…

智能交通(2)——IntelliLight智能交通灯

论文分享:IntelliLight | Proceedings of the 24th ACM SIGKDD International Conference on Knowledge Discovery & Data Mininghttps://dl.acm.org/doi/10.1145/3219819.3220096摘要 智能交通灯控制对于高效的交通系统至关重要。目前现有的交通信号灯大多由手…

共模和差模的基本概念

电压电流在导体或导线中传播时,存在两种工作形态:共模和差模。电子设备的信号线在进行相互通信时,至少会存在两根导线以形成电传输回路,除此之外,通常还存在第三个导体,即“参考地”。当信号正常传输时&…

JAVA学习笔记-JAVA基础语法-DAY19-File类、递归

第一章 File类 1.1 概述 java.io.File 类是文件和目录路径名的抽象表示,主要用于文件和目录的创建、查找和删除等操作。 1.2 构造方法 public File(String pathname) :通过将给定的路径名字符串转换为抽象路径名来创建新的 File实例。public File(St…

go Channel 原理 (一)

Channel 设计原理 不要通过共享内存的方式进行通信,而是应该通过通信的方式共享内存。 在主流编程语言中,多个线程传递数据的方式一般都是共享内存。 Go 可以使用共享内存加互斥锁进行通信,同时也提供了一种不同的并发模型,即通…