15.模版模式设计思想

简介: 模版模式是一种行为设计模式,它定义了一个操作中的算法骨架,而将一些步骤延迟到子类中实现。这种方式让子类可以在不改变算法结构的情况下重新定义算法的某些特定步骤。文章详细介绍了模版模式的基础概念、应用场景、实现原理及优缺点,并通过具体案例深入解析了模版模式的使用方法。适合初学者和有一定经验的开发者深入学习。

15.模版模式设计思想

目录介绍

  • 01.模版模式基础
    • 1.1 模版模式由来
    • 1.2 模版模式定义
    • 1.3 模版模式场景
    • 1.4 模版模式思考
    • 1.5 模版模式特点
    • 1.6 理解模版唯一性
    • 1.7 主要解决问题
  • 02.模版模式原理
    • 2.1 罗列一个场景
    • 2.2 用例子理解模版
    • 2.3 需求普通实现
    • 2.4 案例演变实现
    • 2.5 模版模式实现步骤
  • 03.模版模式结构
    • 3.1 模版标准案例
    • 3.2 模版模式结构
    • 3.3 模版模式时序图
  • 04.模版模式案例分析
    • 4.1 角色分析
    • 4.2 拓展一个场景
    • 4.3 模版模式实践
  • 05.模版者模式分析
    • 5.1 模版模式优点
    • 5.2 模版模式缺点
    • 5.3 使用建议说明
    • 5.4 思考题考察
  • 06.观察者模式总结
    • 6.1 总结一下学习
    • 6.2 更多内容推荐

推荐一个好玩网站

一个最纯粹的技术分享网站,打造精品技术编程专栏!编程进阶网

https://yccoding.com/

关于设计模式,所有的代码都放到了该项目。设计模式大全

01.模版模式基础介绍

1.1 模版模式由来

在软件构建过程中,对于某一项任务,它常常有稳定的整体操作结构,但各个子步骤却有很多改变的需求,或者由于固有的原因(比如框架与应用之间的关系)而无法和任务的整体结构同时实现。

如何在确定稳定操作结构的前提下,来灵活应对各个子步骤的变化或者晚期实现需求?如何保证架构逻辑的正常执行,而不被子类破坏 ?这个时候可以用模版模式!

1.2 模版模式定义

模板方法模式是类的行为模式。

模板模式(Template)将定义的算法抽象成一组步骤,在抽象类种定义算法的骨架,把具体的操作留给子类来实现。

模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。

1.3 模版模式场景

常见模板模式运用场景如下:

  1. Java Servlet:HttpServlet 就是使用了模板模式。HttpServlet 类定义了 service() 方法作为模板方法,子类需要实现 doGet()、doPost() 等方法来处理具体的 HTTP 请求。
  2. Spring Framework:例如,JdbcTemplate 使用了模板模式来简化 JDBC 数据访问代码,定义了模板方法来执行数据库操作,具体的 SQL 语句和参数由子类提供。

总结:当存在一些通用的方法,可以在多个子类中共用时。

1.4 模版模式思考

实际开发中常常会遇到,代码骨架类似甚至相同,只是具体的实现不一样的场景。

例如:休假流程都有开启、编辑、驳回、结束。共享单车都是先开锁、骑行、上锁、付款。每个流程都包含这几个步骤,不同的是不同的流程实例它们的内容不一样。你该如何设计?

1.5 模版模式特点

模板模式的主要特点包括:

  1. 定义一个算法的骨架,将一些步骤留给子类实现。
  2. 允许子类在不改变算法结构的基础上,重新定义某些步骤。
  3. 适用于处理包含一系列基本相同步骤的过程,但某些步骤可能有不同的实现。

1.6 主要解决问题

解决在多个子类中重复实现相同的方法的问题,通过将通用方法抽象到父类中来避免代码重复。

02.模版模式原理

2.1 罗列一个场景

以生活中买菜做饭的例子来写个Demo,烧饭一般都是买菜、洗菜、烹饪、装盘四大过程。中国自古有八大菜系,制作方式肯定都避不开这四个过程。那在模板模式中如何实现呢?

2.2 用例子理解模版

这些大的步骤固定,不同的是每个实例的具体实现细节不一样。这些类似的业务我们都可以使用模板模式实现。

2.3 需求普通实现

关于实现买菜做饭,做川菜和徽菜。最原始的实现如下所示:

private void cook() {
   
    System.out.println("----------川菜制作------------");
    Cooking chuanCaiService = new Cooking(0);
    chuanCaiService.process();
    System.out.println("-----------徽菜制作-----------");
    Cooking huiCaiService = new Cooking(1);
    huiCaiService.process();
}

public class Cooking {
   

    //type是0表示川菜
    //type是1表示徽菜
    private int type;
    public Cooking(int type) {
   
        this.type = type;
    }

    public void process() {
   
        shopping();
        wash();
        cooking();
        dishedUp();
    }

    protected void shopping() {
   
        if (type == 0) {
   
            System.out.println("买菜:黑猪肉一斤,蒜头5个");
        } else if (type == 1){
   
            System.out.println("买菜:新鲜鱼一条,红辣椒五两");
        }

    }

    protected void wash() {
   
        if (type == 0) {
   
            System.out.println("清洗:猪肉洗净,蒜头去皮");
        } else if (type == 1){
   
            System.out.println("清洗:红椒洗净切片,鱼头半分");
        }

    }

    protected void cooking() {
   
        if (type == 0) {
   
            System.out.println("烹饪:大火翻炒,慢火闷油");
        } else if (type == 1){
   
            System.out.println("装盘:用长形盘子装盛");
        }
    }

    protected void dishedUp() {
   
        if (type == 0) {
   
            System.out.println("装盘:深碗盛起,热油浇拌");
        } else if (type == 1){
   
            System.out.println("烹饪:鱼头水蒸,辣椒过油");
        }
    }
}

你有没有发现这样写,要是后期在拓展一个鲁菜,粤菜。这样就会修改原代码,会破坏代码的开闭原则。或者我想修改一下不同菜系的做菜步骤,那就导致代码非常难以修改。

2.4 案例演变实现

创建一个抽象类,它的模板方法被设置为 final。为防止恶意操作,一般模板方法都加上 final 关键词。

public abstract class AbstractCookingService {
   
    //买菜
    protected abstract void shopping();
    //清洗
    protected abstract void wash();
    //烹饪
    protected abstract void cooking();
    //装盘
    protected abstract void dishedUp();

    public final void process() {
   
        shopping();
        wash();
        cooking();
        dishedUp();
    }
}

创建实现了上述抽象类的子类。

/**
 * 徽菜制作大厨
 */
public class HuiCaiChef extends AbstractCookingService {
   

    @Override
    protected void shopping() {
   
        System.out.println("买菜:新鲜鱼一条,红辣椒五两");
    }

    @Override
    protected void wash() {
   
        System.out.println("清洗:红椒洗净切片,鱼头半分");
    }

    @Override
    protected void cooking() {
   
        System.out.println("烹饪:鱼头水蒸,辣椒过油");
    }

    @Override
    protected void dishedUp() {
   
        System.out.println("装盘:用长形盘子装盛");
    }
}

/**
 * 川菜制作大厨
 */
public class ChuanCaiChef extends AbstractCookingService {
   

    @Override
    protected void shopping() {
   
        System.out.println("买菜:黑猪肉一斤,蒜头5个");
    }

    @Override
    protected void wash() {
   
        System.out.println("清洗:猪肉洗净,蒜头去皮");
    }

    @Override
    protected void cooking() {
   
        System.out.println("烹饪:大火翻炒,慢火闷油");
    }

    @Override
    protected void dishedUp() {
   
        System.out.println("装盘:深碗盛起,热油浇拌");
    }
}

然后测试演示一下

private void test() {
   
    System.out.println("----------川菜制作------------");
    AbstractCookingService chuanCaiService = new ChuanCaiChef();
    chuanCaiService.process();
    System.out.println("-----------徽菜制作-----------");
    AbstractCookingService huiCaiService = new HuiCaiChef();
    huiCaiService.process();
}

在模板模式中,定义了一个算法的框架,将算法的具体步骤延迟到子类中实现。这种模式允许子类重写算法的特定步骤而不改变算法的结构。

模板模式中通常包含两个角类,一个模板类和一个具体类,模板类就是一个算法框架。

2.5 模版模式实现步骤

模板模式也没什么高深莫测的,简单来说就是三大步骤:

  1. 创建一个抽象类,定义几个抽象方法和一个final修饰的模板方法,而模板方法中设定了抽象方法的执行顺序或逻辑。
  2. 无论子类有多少个,只需要继承该抽象类,实现父类的抽象方法重写自己的业务。
  3. 根据不同的需求创建不同的子类实现,每次调用的地方只需调用模板方法,即可完成特定的模板流程。

03.模版模式结构

3.1 模版标准案例

3.2 模版模式结构

模板模式的主要角色包括:

  1. 抽象类(AbstractClass):负责实现模板方法,并声明在模板方法中所使用的抽象方法。
  2. 具体类(ConcreteClass):实现抽象类中的抽象方法。
  3. 客户端(Client):使用具体类继承的模板方法。

3.3 模版模式时序图

04.模版模式案例分析

4.1 角色分析

抽象类(Abstract):定义了算法骨架,包含一个或多个抽象方法,这些方法由子类来具体实现。抽象类中通常还包含一个模板方法,用来调用抽象方法和具体方法,控制算法的执行顺序;还可以定义钩子方法,用于在算法中进行条件控制。

具体类(Concrete Class):继承抽象类,实现抽象方法。

4.2 拓展一个场景

以订外卖为例,解释一下模板模式。假设订外卖的过程包含三个步骤:选择外卖、支付、取外卖、是否打赏。

我们可以定义一个OderFood的抽象类,那么选择外卖就可以是抽象方法,需要子类取实现它,支付和取外卖可以定义为具体方法,另外是否打赏为钩子方法,子类可以决定是否对算法的不同进行挂钩。

还需要定义一个模板方法,用以控制流程;不同的商家,如KFC、星巴克就是具体类。

4.3 模版模式实践

OrderFood——抽象类(Abstract)

/**
 * @author Created by njy on 2023/6/24
 * 1.抽象类(Abstract Class):点外卖
 * 包含选择外卖、支付、取外卖三个方法,
 * 其中选择外卖为抽象方法,需要子类实现
 * 支付、取外卖为具体方法
 * 另外是否打赏为钩子方法,子类可以决定是否对算法的不同进行挂钩
 */
public abstract class OrderFood {
   

    //模板方法
    public void order(){
   
        selectFood();
        pay();
        getFood();
    }
    //选择外卖   抽象方法 由子类实现具体细节
    public abstract void selectFood();
    //是否打赏   钩子方法 可以重写来做条件控制
    public boolean isGiveAward(){
   
        return false;
    }
    //-------具体方法----------
    public void pay(){
   
        System.out.println("支付成功,外卖小哥正在快马加鞭~~");
    }

    //取外卖
    public void getFood(){
   
        System.out.println("取到外卖");
        if (isGiveAward()){
   
            System.out.println("打赏外卖小哥");
        }
    }
}

具体类(Concrete Class)

/**
 * 具体类(Concrete Class):星巴克
 */
public class Starbucks extends OrderFood{
   

    //实现父类方法
    @Override
    public void selectFood() {
   
        System.out.println("一杯抹茶拿铁");
    }

    //重写钩子方法,打赏外卖小哥
    @Override
    public boolean isGiveAward(){
   
        return true;
    }
}

/**
 * 具体类(Concrete Class):KFC
 */
public class KFC extends OrderFood{
   
    @Override
    public void selectFood() {
   
        System.out.println("一份汉堡炸鸡四件套");
    }
}

测试一下,代码如下:

//星巴克(重写了钩子方法,打赏外卖小哥)
OrderFood orderFood=new Starbucks();
orderFood.order();
System.out.println("--------KFC------------");
//KFC
OrderFood orderFood1=new KFC();
orderFood1.order();

05.模版者模式分析

5.1 模版模式优点

  1. 封装不变部分:算法的不变部分被封装在父类中。
  2. 扩展可变部分:子类可以扩展或修改算法的可变部分。
  3. 提取公共代码:减少代码重复,便于维护。

5.2 模版模式缺点

  1. 类数目增加:每个不同的实现都需要一个子类,可能导致系统庞大。

5.3 使用建议说明

  1. 当有多个子类共有的方法且逻辑相同时,考虑使用模板方法模式。
  2. 对于重要或复杂的方法,可以考虑作为模板方法定义在父类中。

注意事项:为了防止恶意修改,模板方法通常使用final关键字修饰,避免被子类重写。

5.4 思考题考察

需求1: 实现字符打印和字符串打印两种不同的打印样式。

分析和实现:定义一个抽象类AbstractDisplay其中包含模板方法display,两个实现模板的具体类,CharDisplay和StringDisplay。具体可以看:TemplateDesign

需求2: 做菜的步骤一般是:洗锅 --> 炒菜 --> 洗碗 ,不同的菜,只是炒菜这一个步骤具体细节是不同的。然后做一个煮糖醋鲤鱼,小炒肉,你该如何实现?

分析和实现:整体流程是一样的,有些步骤一样,有些步骤不一样,但是不使用模板模式,需要每个类都重写一遍方法,这个时候可以用模版模式实现。具体可以看:TemplateDesign

06.观察者模式总结

6.1 总结一下学习

  1. 定义:在模板模式(Template Pattern)中,一个抽象类公开定义了执行它的方法的方式/模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行。这种类型的设计模式属于行为型模式。
  2. 意图:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤
  3. 主要解决:一些方法通用,却在每一个子类都重新写了这一方法。
  4. 何时使用:有一些通用的方法。
  5. 如何解决:将这些通用算法抽象出来。
  6. 关键代码:在抽象类实现,其他步骤在子类实现。
  7. 优点: 1、封装不变部分,扩展可变部分。 2、提取公共代码,便于维护。 3、行为由父类控制,子类实现。
  8. 缺点:每一个不同的实现都需要一个子类来实现,导致类的个数增加,使得系统更加庞大。
  9. 使用场景: 1、有多个子类共有的方法,且逻辑相同。 2、重要的、复杂的方法,可以考虑作为模板方法。

6.2 更多内容推荐

模块 描述 备注
GitHub 多个YC系列开源项目,包含Android组件库,以及多个案例 GitHub
博客汇总 汇聚Java,Android,C/C++,网络协议,算法,编程总结等 YCBlogs
设计模式 六大设计原则,23种设计模式,设计模式案例,面向对象思想 设计模式
Java进阶 数据设计和原理,面向对象核心思想,IO,异常,线程和并发,JVM Java高级
网络协议 网络实际案例,网络原理和分层,Https,网络请求,故障排查 网络协议
计算机原理 计算机组成结构,框架,存储器,CPU设计,内存设计,指令编程原理,异常处理机制,IO操作和原理 计算机基础
学习C编程 C语言入门级别系统全面的学习教程,学习三到四个综合案例 C编程
C++编程 C++语言入门级别系统全面的教学教程,并发编程,核心原理 C++编程
算法实践 专栏,数组,链表,栈,队列,树,哈希,递归,查找,排序等 Leetcode
Android 基础入门,开源库解读,性能优化,Framework,方案设计 Android

23种设计模式

23种设计模式 & 描述 & 核心作用 包括
创建型模式
提供创建对象用例。能够将软件模块中对象的创建和对象的使用分离
工厂模式(Factory Pattern)
抽象工厂模式(Abstract Factory Pattern)
单例模式(Singleton Pattern)
建造者模式(Builder Pattern)
原型模式(Prototype Pattern)
结构型模式
关注类和对象的组合。描述如何将类或者对象结合在一起形成更大的结构
适配器模式(Adapter Pattern)
桥接模式(Bridge Pattern)
过滤器模式(Filter、Criteria Pattern)
组合模式(Composite Pattern)
装饰器模式(Decorator Pattern)
外观模式(Facade Pattern)
享元模式(Flyweight Pattern)
代理模式(Proxy Pattern)
行为型模式
特别关注对象之间的通信。主要解决的就是“类或对象之间的交互”问题
责任链模式(Chain of Responsibility Pattern)
命令模式(Command Pattern)
解释器模式(Interpreter Pattern)
迭代器模式(Iterator Pattern)
中介者模式(Mediator Pattern)
备忘录模式(Memento Pattern)
观察者模式(Observer Pattern)
状态模式(State Pattern)
空对象模式(Null Object Pattern)
策略模式(Strategy Pattern)
模板模式(Template Pattern)
访问者模式(Visitor Pattern)

6.3 更多内容

目录
相关文章
|
9天前
|
存储 人工智能 弹性计算
阿里云弹性计算_加速计算专场精华概览 | 2024云栖大会回顾
2024年9月19-21日,2024云栖大会在杭州云栖小镇举行,阿里云智能集团资深技术专家、异构计算产品技术负责人王超等多位产品、技术专家,共同带来了题为《AI Infra的前沿技术与应用实践》的专场session。本次专场重点介绍了阿里云AI Infra 产品架构与技术能力,及用户如何使用阿里云灵骏产品进行AI大模型开发、训练和应用。围绕当下大模型训练和推理的技术难点,专家们分享了如何在阿里云上实现稳定、高效、经济的大模型训练,并通过多个客户案例展示了云上大模型训练的显著优势。
|
12天前
|
存储 人工智能 调度
阿里云吴结生:高性能计算持续创新,响应数据+AI时代的多元化负载需求
在数字化转型的大潮中,每家公司都在积极探索如何利用数据驱动业务增长,而AI技术的快速发展更是加速了这一进程。
|
3天前
|
并行计算 前端开发 物联网
全网首发!真·从0到1!万字长文带你入门Qwen2.5-Coder——介绍、体验、本地部署及简单微调
2024年11月12日,阿里云通义大模型团队正式开源通义千问代码模型全系列,包括6款Qwen2.5-Coder模型,每个规模包含Base和Instruct两个版本。其中32B尺寸的旗舰代码模型在多项基准评测中取得开源最佳成绩,成为全球最强开源代码模型,多项关键能力超越GPT-4o。Qwen2.5-Coder具备强大、多样和实用等优点,通过持续训练,结合源代码、文本代码混合数据及合成数据,显著提升了代码生成、推理和修复等核心任务的性能。此外,该模型还支持多种编程语言,并在人类偏好对齐方面表现出色。本文为周周的奇妙编程原创,阿里云社区首发,未经同意不得转载。
|
9天前
|
人工智能 运维 双11
2024阿里云双十一云资源购买指南(纯客观,无广)
2024年双十一,阿里云推出多项重磅优惠,特别针对新迁入云的企业和初创公司提供丰厚补贴。其中,36元一年的轻量应用服务器、1.95元/小时的16核60GB A10卡以及1元购域名等产品尤为值得关注。这些产品不仅价格亲民,还提供了丰富的功能和服务,非常适合个人开发者、学生及中小企业快速上手和部署应用。
|
19天前
|
自然语言处理 数据可视化 前端开发
从数据提取到管理:合合信息的智能文档处理全方位解析【合合信息智能文档处理百宝箱】
合合信息的智能文档处理“百宝箱”涵盖文档解析、向量化模型、测评工具等,解决了复杂文档解析、大模型问答幻觉、文档解析效果评估、知识库搭建、多语言文档翻译等问题。通过可视化解析工具 TextIn ParseX、向量化模型 acge-embedding 和文档解析测评工具 markdown_tester,百宝箱提升了文档处理的效率和精确度,适用于多种文档格式和语言环境,助力企业实现高效的信息管理和业务支持。
3941 3
从数据提取到管理:合合信息的智能文档处理全方位解析【合合信息智能文档处理百宝箱】
|
9天前
|
算法 安全 网络安全
阿里云SSL证书双11精选,WoSign SSL国产证书优惠
2024阿里云11.11金秋云创季活动火热进行中,活动月期间(2024年11月01日至11月30日)通过折扣、叠加优惠券等多种方式,阿里云WoSign SSL证书实现优惠价格新低,DV SSL证书220元/年起,助力中小企业轻松实现HTTPS加密,保障数据传输安全。
522 3
阿里云SSL证书双11精选,WoSign SSL国产证书优惠
|
4天前
|
人工智能 自然语言处理 前端开发
用通义灵码,从 0 开始打造一个完整APP,无需编程经验就可以完成
通义灵码携手科技博主@玺哥超carry 打造全网第一个完整的、面向普通人的自然语言编程教程。完全使用 AI,再配合简单易懂的方法,只要你会打字,就能真正做出一个完整的应用。本教程完全免费,而且为大家准备了 100 个降噪蓝牙耳机,送给前 100 个完成的粉丝。获奖的方式非常简单,只要你跟着教程完成第一课的内容就能获得。
|
15天前
|
安全 数据建模 网络安全
2024阿里云双11,WoSign SSL证书优惠券使用攻略
2024阿里云“11.11金秋云创季”活动主会场,阿里云用户通过完成个人或企业实名认证,可以领取不同额度的满减优惠券,叠加折扣优惠。用户购买WoSign SSL证书,如何叠加才能更加优惠呢?
992 3
|
7天前
|
数据采集 人工智能 API
Qwen2.5-Coder深夜开源炸场,Prompt编程的时代来了!
通义千问团队开源「强大」、「多样」、「实用」的 Qwen2.5-Coder 全系列,致力于持续推动 Open Code LLMs 的发展。
|
13天前
|
机器学习/深度学习 存储 人工智能
白话文讲解大模型| Attention is all you need
本文档旨在详细阐述当前主流的大模型技术架构如Transformer架构。我们将从技术概述、架构介绍到具体模型实现等多个角度进行讲解。通过本文档,我们期望为读者提供一个全面的理解,帮助大家掌握大模型的工作原理,增强与客户沟通的技术基础。本文档适合对大模型感兴趣的人员阅读。
445 18
白话文讲解大模型| Attention is all you need