【设计模式】行为型-模板方法模式

方法千变万化,心灵如潮,模板如画,画出生活的韵味。

文章目录

  • 一、茶与咖啡
  • 二、模板方法模式
  • 三、模板方法模式的核心组成
  • 四、运用模板方法模式
  • 五、模板方法模式的应用场景
  • 六、小结
  • 推荐阅读

一、茶与咖啡

场景假设:我们需要完成茶和咖啡的制作。

// 咖啡类
class Coffee {
    // 准备配方的方法
    void prepareRecipe() {
        boilWater(); // 煮沸水
        brewCoffeeGrinds(); // 冲泡咖啡
        pourInCup(); // 倒入杯子
        addSugarAndMilk(); // 添加糖和牛奶
    }

    // 下面是每个步骤的具体实现
    void boilWater() { System.out.println("Boiling water"); }
    void brewCoffeeGrinds() { System.out.println("Dripping Coffee through filter"); }
    void pourInCup() { System.out.println("Pouring into cup"); }
    void addSugarAndMilk() { System.out.println("Adding Sugar and Milk"); }
}

// 茶类
class Tea {
    // 准备配方的方法
    void prepareRecipe() {
        boilWater(); // 煮沸水
        steepTeaBag(); // 浸泡茶包
        pourInCup(); // 倒入杯子
        addLemon(); // 添加柠檬
    }

    // 下面是每个步骤的具体实现
    void boilWater() { System.out.println("Boiling water"); }
    void steepTeaBag() { System.out.println("Steeping the tea"); }
    void pourInCup() { System.out.println("Pouring into cup"); }
    void addLemon() { System.out.println("Adding Lemon"); }
}

咖啡和茶创建两个不同的类,并在每个类中实现整个制作过程。这将导致大量的代码重复,因为煮沸水和倒入杯子的步骤对于咖啡和茶来说都是相同的。在这个例子中,boilWaterpourInCup 在两个类中都是重复的。如果我们需要修改这些步骤的实现,我们需要在两个类中都进行修改,这就增加了维护的复杂性。此外,如果我们需要添加一个新的饮料类型,我们又需要复制大量的代码。

二、模板方法模式

模板方法模式是一种行为型设计模式,它定义了一个算法的骨架,将算法的某些步骤延迟到子类中实现。这样可以在不改变算法结构的情况下,允许子类重新定义算法中的特定步骤。

该模式提供了一个模板(即抽象类),其中包含了一系列的方法,其中某些方法是抽象的,需要由子类实现,而其他方法是具体的,并且已经实现好了。这样,当客户端调用模板方法时,将按照模板的定义来执行一系列的步骤,其中部分步骤可能在子类中有不同的实现。

三、模板方法模式的核心组成

模板方法模式的核心组件主要包括以下几个部分:

  1. 抽象类(Abstract Class):这个类定义了一系列的方法,包括具体的方法(实现了特定功能)和抽象的方法(没有具体实现,需要子类来提供实现)。此外,抽象类还定义了一个模板方法,这个方法按照特定的顺序调用上述的一系列方法。
  2. 具体类(Concrete Class):这个类继承自抽象类,并提供抽象方法的具体实现。当模板方法被调用时,这些具体的实现将被执行。
  3. 模板方法(Template Method):在抽象类中定义,这个方法包含了一个算法的骨架。它按照特定的顺序调用一系列的方法。其中一些方法是具体的,由抽象类提供实现;另一些方法是抽象的,由具体类提供实现。
  4. 钩子方法(Hook Method):这是一种特殊的方法,它在抽象类中通常没有做任何事或者只提供默认的实现,但是它提供了一个扩展点,允许子类在必要时覆盖它。

在这里插入图片描述

在这个类图中:

  1. AbstractClass 是一个抽象类,它定义了 templateMethod()(模板方法)和两个抽象方法 primitiveOperation1() 和 primitiveOperation2()。模板方法定义了一个算法的骨架,按照特定的顺序调用一系列的方法。其中一些方法是具体的,由抽象类提供实现;另一些方法是抽象的,由具体类提供实现。
  2. ConcreteClass 是一个具体类,它继承自 AbstractClass 并提供抽象方法的具体实现。当模板方法被调用时,这些具体的实现将被执行。

四、运用模板方法模式

场景假设:我们需要制作茶、咖啡等多种饮料。

  1. 定义抽象类:首先,我们需要定义一个抽象类,这个类包含了制作饮料的通用步骤。

    // 抽象类:含有咖啡因的饮料
    abstract class CaffeineBeverage {
        // 这是我们的模板方法。它定义了算法的步骤。
        final void prepareRecipe() {
            boilWater(); // 第一步:煮沸水
            brew(); // 第二步:冲泡。但是我们并不知道是冲泡咖啡还是茶,所以这是一个抽象方法。
            pourInCup(); // 第三步:倒入杯子
            addCondiments(); // 第四步:添加调料。但是我们并不知道是添加什么调料,所以这是一个抽象方法。
        }
    
        // 这两个方法是抽象的,也就是说,我们需要子类来提供具体的实现。
        abstract void brew();
        abstract void addCondiments();
    
        // 这两个方法是具体的,也就是说,它们在所有子类中都是一样的,所以我们可以将它们的实现放在这个抽象类中。
        void boilWater() { System.out.println("Boiling water"); }
        void pourInCup() { System.out.println("Pouring into cup"); }
    }
    

    在这个抽象类 CaffeineBeverage 中,我们定义了一个模板方法 prepareRecipe(),它按照特定的顺序调用一系列的步骤。其中 brew() 和 addCondiments() 是抽象的,我们需要子类来提供具体的实现。

  2. 定义具体类:然后,我们为每种饮料定义一个具体的类,这个类继承自抽象类,并提供抽象方法的具体实现。

    // 具体类:咖啡
    class Coffee extends CaffeineBeverage {
        // 对于咖啡来说,冲泡就是用热水过滤咖啡
        void brew() {
            System.out.println("Dripping Coffee through filter");
        }
    
        // 对于咖啡来说,添加的调料是糖和牛奶
        void addCondiments() {
            System.out.println("Adding Sugar and Milk");
        }
    }
    
    // 具体类:茶
    class Tea extends CaffeineBeverage {
        // 对于茶来说,冲泡就是用热水浸泡茶叶
        void brew() {
            System.out.println("Steeping the tea");
        }
    
        // 对于茶来说,添加的调料是柠檬
        void addCondiments() {
            System.out.println("Adding Lemon");
        }
    }
    

    在这两个具体类 Coffee 和 Tea 中,我们提供了 brew() 和 addCondiments() 方法的具体实现。当模板方法 prepareRecipe() 被调用时,这些具体的实现将被执行。

五、模板方法模式的应用场景

模板方法模式通常在以下情况下使用:

  1. 算法框架固定,但具体实现可变:当一个算法的框架已经确定,但其中的一些步骤的具体实现可能会随着应用场景的变化而变化时,可以使用模板方法模式。这样,可以将算法的框架定义在抽象模板中,而将可变的部分留给子类来实现。
  2. 避免代码重复:当多个类中存在相似的算法流程,但具体步骤略有不同,为避免代码重复,可以将这些公共部分提取到抽象模板中,从而避免代码重复,提高代码的复用性。
  3. 提供算法定制化的扩展点:模板方法模式提供了一种在不改变算法结构的情况下,允许子类重新定义算法中特定步骤的方法。这样,可以为客户端提供一种定制化的扩展点,允许客户端根据需要定制算法的具体实现。
  4. 框架设计:模板方法模式在框架设计中也经常被使用,例如在 Web 框架中,可以定义一个抽象的控制器类作为模板,其中包含了请求处理的流程,而具体的控制器类则根据具体业务需求来实现这些步骤。

六、小结

模板方法模式能够帮助我们定义算法的骨架,并允许子类定制算法的具体实现,从而提高了代码的复用性和灵活性,是一种非常有用的设计模式。在实际开发中,我们可以根据具体情况来灵活运用模板方法模式,提高代码的可维护性和扩展性。

推荐阅读

  1. Spring 三级缓存
  2. 深入了解 MyBatis 插件:定制化你的持久层框架
  3. Zookeeper 注册中心:单机部署
  4. 【JavaScript】探索 JavaScript 中的解构赋值
  5. 深入理解 JavaScript 中的 Promise、async 和 await

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

测试开发面经分享,面试七天速成 DAY2

1. TCP和UDP的区别 a. TCP是面向连接的协议,而UDP是无连接的协议。 b. TCP提供可靠的数据传输,保证数据的有序性和完整性,而UDP则不提供这些保证。 c. TCP使用流控制和拥塞控制机制,以确保数据的可靠传输,而UDP没有这…

HCIE-QOS基本原理

QOS基本原理 QOS概述什么是QOSQoS服务模型区分服务模型QoS常用技术 (DiffServ模型)QoS数据处理流程 (DiffServ模型) QoS流分类和流标记QoS数据处理流程为什么需要流分类和流标记 简单流分类外部优先级 - VLAN报文外部优先级 - MPLS报文外部优先级 - IP报文各外部优先级间的对应…

Kafka集成flume

1.flume作为生产者集成Kafka kafka作为flume的sink,扮演消费者角色 1.1 flume配置文件 vim $kafka/jobs/flume-kafka.conf # agent a1.sources r1 a1.sinks k1 a1.channels c1 c2# Describe/configure the source a1.sources.r1.type TAILDIR #记录最后监控文件…

计算机视觉基础课程知识点总结

图像滤波 相关: 核与图像同向应用,不翻转。 卷积: 核在应用前翻转,广泛用于信号处理和深度学习(现在常说的二维卷积就是相关)。 内积: 向量化的点积操作,是相关和卷积的一部分。 模板匹配:通过在图像中…

Go变量作用域精讲及代码实战

1. 变量的作用域概述 在编程中,变量的作用域(Scope)定义了变量在程序中的可见性和生命周期。理解变量的作用域对于编写健壮且可维护的代码至关重要。Go语言(简称Go)提供了几种不同的作用域类型,使得开发者可…

13600KF+3060Ti,虚拟机安装macOS 14,2024年6月

距离上次装macOS虚拟机已经有一段时间了,macOS系统现在大版本升级的速度也是越来越快了,由于Office只支持最新三个版本的macOS,所以现在保底也得安装macOS 12了,我这次是用macOS 14做实验,13和12的安装方式和macOS 14一…

Word同行内的文字如何左右分别对齐

先打开标尺(视图-标尺) 开右边,选一个制表位置,比如我选34 切回开始,点段落段落右下角 然后 然后 我修改为35(因为“6月13日”总共3个字符) 在文字中间按下Tab键,效果如下

视频生成模型 Dream Machine 开放试用;微软将停止 Copilot GPTs丨 RTE 开发者日报 Vol.224

开发者朋友们大家好: 这里是 「RTE 开发者日报」 ,每天和大家一起看新闻、聊八卦。我们的社区编辑团队会整理分享 RTE(Real-Time Engagement) 领域内「有话题的 新闻 」、「有态度的 观点 」、「有意思的 数据 」、「有思考的 文…

《C++程序设计》银行管理系统

莫思身外无穷事 且尽生前有限杯 我们先来看一下项目需求: 【场景】 在日常生活中,我们普遍接触到窗口服务系统,如到银行柜台办理业务、景区现场购买门票等。当需要办理业务的顾客数超过窗口数量时,我们需遵循排队等待原则。 【需…

微服务 | Springboot整合Dubbo+Nacos实现RPC调用

官网:Apache Dubbo 随着互联网技术的飞速发展,越来越多的企业和开发者开始关注微服务架构。微服务架构可以将一个大型的应用拆分成多个独立、可扩展、可维护的小型服务,每个服务负责实现应用的一部分功能。这种架构方式可以提高开发效率&…

怎么用住宅代理IP?使用住宅代理IP有哪些好处?

如何使用住宅代理IP: 使用住宅代理IP主要涉及以下几个步骤: 选择合适的代理IP供应商: 考虑供应商的可靠性、代理IP的质量、速度、稳定性以及价格。选择信誉良好且服务稳定的供应商,确保获得高质量的代理IP服务。配置代理IP&#…

2024年中漫谈

不知不觉,2024年已来到了6月,博主不禁感叹时光易逝,岁月的车轮滚滚向前,永不止步,此刻无关贫穷与富裕,伟大与平凡。 于是乎,宇宙(时空)看似毫无终点,一望无垠…

辽宁普通测径仪升级智能测径仪后都有哪些改进?

关键字: 普通测径仪, 智能测径仪, 测径仪升级, 测径仪特点, 智能测径仪优势, 目前多数厂家测径仪的数据处理方式是单片机计算出最终结果,然后传输到工控机后期处理。这样的电路系统对轧钢现场的高温、高粉尘和强电磁干扰的环境适应性很差,使得同一厂家、…

芯片后端对于芯片设计公司的重要性

在芯片设计流程中,后端设计是一个至关重要的环节,它直接关系到芯片从设计到实际生产的转化,以及最终产品的性能、可靠性、成本和上市时间。 以下是为什么芯片后端非常重要的几个关键原因: 物理实现:后端设计是芯片从逻…

【APP移动端自动化测试】第二节.Appium介绍和常用命令代码实现

文章目录 前言一、Appium介绍和安装二、python代码功能实现 2.1 hello appium 参数详解 2.2 在脚本内启动其他app 2.3 获取app的包名和界面名 2.4 关闭app和驱动对象 2.5 安装和卸载以及是否安装app 2.6 将应用置于后台总结 前言 一、Appium介绍…

Vertical Layout 、Horizontal Layout 实验窗体自适应布局

实验目的 学习实验使用布局实现如下自适应界面 窗体邮件,布局设置为垂直布局 用同样的方法,添加groupbox,并右键设置为水平布局 拖入一个Horizontal Layout,然后拖入button,拖入 Horizontal Spacer 遇到一个问题&#…

openh264 帧内预测编码过程源码分析

函数关系 说明: 可以看到完成帧内预测编码的核心函数就是 WelsMdI16x16、WelsMdI4x4、WelsMdI4x4Fast 、WelsMdIntraChroma 四个函数。 原理 WelsMdI16x16函数 功能:针对16x16像素块的帧内模式决策过程: 局部变量申明;根据宏块…

三星公布尖端芯片进展 | 百能云芯

三星电子在本周三举办的年度晶圆制造盛会上,揭开了未来多项技术革新的神秘面纱,并宣布其晶圆制造业务将整合全球领先的记忆芯片、晶圆制造及封装服务,为AI芯片客户提供一站式服务,以加速其生产进程。 三星强调,客户仅需…

万元补贴助力开源项目!「GitCode 开源摘星计划」已开启

当我们谈到开源项目运作的痛点,都在谈什么?找不到对项目感兴趣的开发者,始终是几个人维护…代码托管平台上开源项目众多,得不到有力的流量支持,项目被淹没在茫茫列表里…社区运营要专人来做,成本太高… 这…

【StructueEngineering】Wind Load Combination Patterns风荷载组合模式

文章目录 Combination PatternsBasic Rules of Combinations组合的基本规律Specific Combination Patterns1. First 8 Combinations (1 to 8)2. Middle 8 Combinations (9 to 16)3. Last 8 Combinations (17 to 24) Summary of CombinationsKey Variables and Parameters with …