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 更多内容

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,126评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,254评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,445评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,185评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,178评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,970评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,276评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,927评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,400评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,883评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,997评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,646评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,213评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,204评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,423评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,423评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,722评论 2 345

推荐阅读更多精彩内容

  • 02.工厂模式设计思想 目录介绍 01.工厂模式设计1.1 工厂模式类型1.2 工厂模式思考1.3 思考一个题目 ...
    杨充211阅读 59评论 0 1
  • 03.建造者模式设计思想 目录介绍 01.建造者模式介绍1.1 建造者模式由来1.2 建造者模式定义1.3 建造者...
    杨充211阅读 59评论 0 0
  • 08.装饰者模式设计思想 目录介绍 01.装饰者模式基础1.1 装饰者模式由来1.2 装饰者模式定义1.3 装饰者...
    杨充211阅读 31评论 0 0
  • 10.桥接模式设计思想 目录介绍 01.桥接模式基础1.1 桥接模式由来1.2 桥接模式定义1.3 桥接模式场景1...
    杨充211阅读 49评论 0 0
  • 07.适配器模式设计思想 目录介绍 01.适配器模式基础1.1 适配器模式由来1.2 适配器模式定义1.3 适配器...
    杨充211阅读 37评论 0 0