详解设计模式:模版方法模式

news2024/9/24 13:17:35

模板方法模式(Template Method Pattern)也被称为模板模式(Template Pattern),是在 GoF 23 种设计模式中定义了的行为型模式。

模板方法模式 定义一个操作中的算法骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。

本片文章内容包括:关于模版方法模式、观察者模式 Demo、模版方法模式的应用(InputStream 中的模版方法模式)


文章目录

    • 一、关于模版方法模式
        • 1、关于模版方法模式
        • 2、关于模版方法模式的构成
        • 3、关于抽象模板的方法组成
        • 4、关于模版方法模式的XML
        • 5、关于模版方法模式的使用场景
        • 6、关于模版方法模式的优缺点
    • 二、观察者模式 Demo
        • 1、Demo 设计
        • 2、Demo 实现
        • 3、Demo 测试
    • 三、模版方法模式的应用(InputStream 中的模版方法模式)


一、关于模版方法模式

1、关于模版方法模式

模板方法模式(Template Method Pattern)也被称为模板模式(Template Pattern),是在 GoF 23 种设计模式中定义了的行为型模式。

模板方法模式 定义一个操作中的算法骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。

模板方法模式 核心:处理某个流程的代码已经都具备,但是其中某个节点的代码暂时不能确定。因此,我们采用模版方法模式,将这个节点的代码实现转移给子类完成。即:处理步骤在父类中定义好,具体的实现延迟到子类中定义。

2、关于模版方法模式的构成

模版方法模式主要由 2 种角色构成:

  • 抽象类/抽象模板(Abstract Class):负责给出一个算法的轮廓和骨架。它由一个模板方法和若干个基本方法构成
  • 具体子类/具体实现(Concrete Class):实现抽象类中所定义的抽象方法和钩子方法,它们是一个顶级逻辑的一个组成步骤

3、关于抽象模板的方法组成

抽象模板类,由一个模板方法和若干个基本方法构成:

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

基本方法:是整个算法中的一个步骤,包含以下几种类型:

  • 抽象方法(abstract method):在抽象类中声明,由具体子类实现;
  • 具体方法(specific method):在抽象类中已经实现,在具体子类中可以继承或重写它;
  • 钩子方法:在抽象类中已经实现,包括用于判断的逻辑方法和需要子类重写的空方法两种。

4、关于模版方法模式的XML

image-20221203055215523

5、关于模版方法模式的使用场景

  • 算法的整体步骤很固定,但其中个别部分易变时,这时候可以使用模板方法模式,将容易变的部分抽象出来,供子类实现。
  • 当多个子类存在公共的行为时,可以将其提取出来并集中到一个公共父类中以避免代码重复。首先,要识别现有代码中的不同之处,并且将不同之处分离为新的操作。最后,用一个调用这些新的操作的模板方法来替换这些不同的代码。
  • 当需要控制子类的扩展时,模板方法只在特定点调用钩子操作,这样就只允许在这些点进行扩展。

6、关于模版方法模式的优缺点

# 模版方法模式的优点

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

# 模版方法模式的缺点

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

二、观察者模式 Demo

1、Demo 设计

炒菜的步骤是固定的,我们可以将其简化为倒油、热油、下蔬菜、下酱料、翻炒等步骤,现通过模板方法模式来用代码模拟。

Demo 类图如下:

在这里插入图片描述

2、Demo 实现

# AbstractClass 抽象模板类

public abstract class AbstractClass {
    
    /**
     * 模板方法
     */
    public final void cookProcess() {
        //第一步:倒油
        this.pourOil();
        //第二步:热油
        this.heatOil();
        //第三步:倒蔬菜
        this.pourVegetable();
        //第四步:倒调味料
        this.pourSauce();
        //第五步:翻炒
        this.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 具体子类

public class ConcreteClass_BaoCai extends AbstractClass {

    @Override
    public void pourVegetable() {
        System.out.println("下锅的蔬菜是包菜");
    }

    @Override
    public void pourSauce() {
        System.out.println("下锅的酱料是辣椒");
    }
}
public class ConcreteClass_CaiXin extends AbstractClass {

    @Override
    public void pourVegetable() {
        System.out.println("下锅的蔬菜是菜心");
    }

    @Override
    public void pourSauce() {
        System.out.println("下锅的酱料是蒜蓉");
    }
}

3、Demo 测试

public class Client {
    public static void main(String[] args) {
        //炒手撕包菜
        ConcreteClass_BaoCai baoCai = new ConcreteClass_BaoCai();
        baoCai.cookProcess();

        //炒蒜蓉菜心
        ConcreteClass_CaiXin caiXin = new ConcreteClass_CaiXin();
        caiXin.cookProcess();
    }
}

三、模版方法模式的应用(InputStream 中的模版方法模式)

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

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

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

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

相关文章

若依框架RuoYi项目运行启动教程【傻瓜式教程】

启动若依项目 1.官网下载代码 若依官网 若依在线文档 首先去官网下载代码 链接到码云下载&#xff0c;要么用git下载要么压缩包下载。 然后再IDEA打开项目 想要运行就要搭建好环境 2.搭建若依环境 按照文档要求配置环境 JDK > 1.8 (推荐1.8版本) Mysql > 5.7.0 (推…

Stable Diffusion 2.0 来了

Stable Diffusion 一经发布&#xff0c;就立刻在业界掀起巨大的波浪。我个人后知后觉&#xff0c;直到 Stable Diffusion V1.4 版本发布&#xff0c;才接触 Stable Diffusion (之前使用的是 Disco Diffusion)。这段时间&#xff0c;SD 团队也没闲着&#xff0c;很快就发布了 V2…

【华为上机真题 2022】停车场车辆统计

&#x1f388; 作者&#xff1a;Linux猿 &#x1f388; 简介&#xff1a;CSDN博客专家&#x1f3c6;&#xff0c;华为云享专家&#x1f3c6;&#xff0c;Linux、C/C、云计算、物联网、面试、刷题、算法尽管咨询我&#xff0c;关注我&#xff0c;有问题私聊&#xff01; &…

【Python】推荐三个好玩的图像处理库

1. 引言 Python是一门高级语言&#xff0c;它可以实现很多功能。Python强大的原因是什么&#xff1f;某种程度上&#xff0c;在于它所拥有的现成的库&#xff0c;使其在编程的各个方向上都易于使用。在本文中&#xff0c;我将向大家展示一些Python库&#xff0c;这些库非常有用…

node.js的模块化

目录 一、模块化的概念 1.什么是模块化 2.编程领域中的模块化 二、node.js中模块的分类 三、require() 加载模块 四. 模块作用域 五、module对象 六、module.exports对象 七、exports对象 八、CommonJS规定: 九、关于包&#xff08;第三方模块&#xff09; 十、解决…

阿里P8高级专家,耗时多年整理SpringBoot指南文档

前言 相信程序员们已经看过甚至动手操作过很多的springboot项目&#xff0c;在项目操作中需要各种插件的支持&#xff0c;其实&#xff0c;可能还有很多大家不知道的但是很方便的操作&#xff0c;小编今天就给大家把这份PDF分享出来&#xff0c;绝对是你以前没有见到过的。 1、…

springboot读取yml文件中的list列表、数组、map集合和对象

前言 springboot配置文件yml类型简单的风格&#xff0c;十分受大家的欢迎&#xff0c;支持字符string类型&#xff0c;支持列表list类型&#xff0c;支持集合map类型&#xff0c;支持数组array类型&#xff0c;支持类对象类型&#xff0c;下面我们来实战下这些形式的配置如何取…

聚观早报 | 国美电器被申请破产清算;首款太阳能汽车投入生产

今日要闻&#xff1a;网传国美电器被申请破产清算&#xff1b;全球首款太阳能汽车投入生产&#xff1b;苹果头显配套系统已改名为xrOS&#xff1b;马斯克计划植入脑机接口设备&#xff1b;特斯拉即将推出自动驾驶出租车网传国美电器被申请破产清算 12 月 2 日消息&#xff0c;据…

网站都变成灰色,有哪些方法可以快速实现?

有些时候我们需要把网站页面变成黑白色或灰色&#xff0c;特别是对于一些需要悼念的日子&#xff0c;以及一些影响力很大的伟人逝世或纪念日的时候&#xff0c;都会让网站的全部网页变成灰色&#xff08;黑白色&#xff09;&#xff0c;以表示我们对逝者或者英雄的缅怀和悼念。…

在校大学生如何申请软著,手把手教会你(内有免费模板)

目录 一.前言 二.以学校为单位全流程申请&#xff08;以我的学校为例&#xff09; 1.问问导员谁负责管软著申请这块的&#xff0c;联系他&#xff0c;问需要什么。 2.为了防止学生买软著转头申请 3.按以下要求准备材料 4.没问题就发给老师&#xff0c;一般要破费一下 5.…

View基础知识-位置大小和滑动

前言 这篇文章可以作为基础看看&#xff0c;但是有时候基础就是细节&#xff0c;不一定所有人都记得&#xff0c;所以基础也要记录一下。都熟悉的话也可以看看其他系列文章&#xff1a; View事件分发机制&#xff08;源码分析篇&#xff09; Android一步一步追踪View的工作原…

【车辆动力】基于Matlab模拟停车动力学

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;修心和技术同步精进&#xff0c;matlab项目合作可私信。 &#x1f34e;个人主页&#xff1a;Matlab科研工作室 &#x1f34a;个人信条&#xff1a;格物致知。 更多Matlab仿真内容点击&#x1f447; 智能优化算法 …

Python 音频处理以及可视化 Amplitude,MFCC,Mel Spectrogram, librosa 库

利用python库 librosa库对于音频文件进行预处理&#xff0c;以及可视化操作。 1. Load Audio Data 导入音频 将音频文件&#xff08;这里使用苹果录音文件 .m4a 格式&#xff09;导入librosa&#xff0c;音频格式可以为其它&#xff08;甚至视频文件mp4也是可以的&#xff09…

【Docker】Dockerfile:常见保留字、使用案例

Dockerfile是用来构建Docker镜像的文本文件&#xff0c;是由一条条构建镜像所需的指令和参数构成的脚本。 官网&#xff1a;链接 构建三步骤 编写Dockerfile文件构建镜像&#xff1a;docker build用镜像运行容器实例&#xff1a;docker run 一、常用的保留字 二、使用案例 要…

Spring MVC统一异常处理的3种方式(附带实例)

在 Spring MVC 应用的开发中&#xff0c;不管是对底层数据库操作&#xff0c;还是业务层或控制层操作&#xff0c;都会不可避免地遇到各种可预知的、不可预知的异常需要处理。 如果每个过程都单独处理异常&#xff0c;那么系统的代码耦合度高&#xff0c;工作量大且不好统一&a…

html5期末大作业:基于html+css+javascript+jquery+bootstarp响应式图书电商HTML模板网上书店(25页)

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

STC 51单片机51——直流电机PWM

//开发板按钮K3和K4用于调速&#xff0c;直流电机接部件电机模块Vcc和O1 #include"reg52.h" #define u8 unsigned char #define u16 unsigned int sbit O1P1^0;//ULN2003 sbit K3P3^2; //减速 sbit K4P3^3; //加速 u8 Flag; u16 T, PWM, Temp;//T为控制周期…

Java项目:ssm赛事打分系统

作者主页&#xff1a;源码空间站2022 简介&#xff1a;Java领域优质创作者、Java项目、学习资料、技术互助 文末获取源码 项目介绍 赛事评分系统&#xff0c;SSM框架。该项目分管理员、裁判、选手三个用户角色。 管理员主要功能&#xff1a; 首页、选手管理、裁判管理、赛事管…

【2022世界杯开源项目实战】使用docker部署world-cup-2022-cli-dashboard数据看板工具

【2022世界杯开源项目实战】使用docker部署world-cup-2022-cli-dashboard数据看板工具一、world-cup-2022-cli-dashboard介绍1.工具介绍2.数据看板的内容二、检查本地docker环境1.检查docker版本2.检查docker状态三、构建world-cup-2022-cli-dashboard的镜像1.下载world-cup-20…

如何用蓝牙实现无线定位(四)--远程定位显示

1. 待救援定位设备 按照下面的针脚使用杜邦线将待救援定位设备的主蓝牙、从蓝牙连接到主控板上&#xff0c;和本地显示时的连接针脚是一样的&#xff0c;但是由于不需要连接OLED&#xff0c;因此不需要堆叠Bigfish。 参考视频 烧录程序如下&#xff08;human.ino&#xff09;&a…