模板方法(Template Method作为Java的设计模式之一,一个词概括其优势特点那就是:抽象步骤

接下来以一个问答的形式进行理解记录

base代码:现在你要制作一个蛋糕,你会很多种做法,我们将制作蛋糕具象化成为代码,如下

public class Cake {public static int METHOD_1 = 1;public static int METHOD_2 = 2;public void make(int method) {System.out.println("make start");if (method == METHOD_1) {// 用方法1做蛋糕} else if (method == METHOD_2) {// 用方法2做蛋糕}System.out.println("make finish");}}

提问1:现在你灵光一闪,又想出一种制作方案你该怎么办?

回答1:你会毫不犹豫的说,追加一个method的static字段,以及追加一个if分支条件判断

public class Cake {......public static int METHOD_3 = 3;public void make(int method) {System.out.println("make start");......} else if (method == METHOD_3) {// 用方法3做蛋糕}......System.out.println("make finish");}}

提问2:这确实是一个解决方案,但是你有没有考虑过如果一个if里面有百余行,而且你又有非常多的制作内容怎么办,怎么解决冗长问题?

也许你会想,就加代码呗,反正我都熟悉。但是如果你不是重头写代码的人,你拿到这个类的时候就有N多种策略超过千行的代码,你是否会吐槽怎么全堆在一起了呢?如果你是一个优秀设计者或leader,review这套代码时能不想去优化吗?

为了更好的可扩展性和可读性我们可以引入模板方法

首先我们应该抽出共通的东西做一个父类(Base类),其次具体的蛋糕制作由子类进一步实现,每一种制作方式我们就拓展一个子类

仔细观察Cake类,你会发现make方法是这个类的核心,make()中便是执行制作的核心代码,为了尽可能将共通的东西都留在父类(base类),我们要进一步将make()中的代码拆分,让其变成众多子步骤方法如下:

public abstract class Cake {final void make() {makeStart();//logmakingCakeGerm();//做蛋糕胚makingCream();//制作奶油wipeCakeGerm();//抹蛋糕胚piping();//裱花makeFinish();//log}private void makeStart() {System.out.println("make start");}protected abstract String makingCakeGerm();protected abstract String makingCream();protected abstract String wipeCakeGerm();protected abstract String piping();private void makeFinish() {System.out.println("make finish");}
}

我们可以看到已经把make方法中的步骤进一步拆分细化,有先做蛋糕胚,再做奶油,然后涂抹到蛋糕胚上,最后裱花

我们来注意几个细节:

1、cake类成为了抽象类,没啥好说的,方法都抽象了

2、make方法增加了final修饰,不希望子类覆写这个方法,防止流程被更改

3、步骤抽象化,这是模板方法的核心,步骤的具体实现交由子类自行实现,每一种蛋糕都可以用不同的子类独立实现,这样可读性就大大提高了,而且扩展也非常方便,只需要实现一个新的子类即可

接下来我们实现具体的蛋糕子类:

我们这里可以这样想,蛋糕胚基本上没什么差别,抹奶油也都是常规操作,不一样的是制作什么样的奶油以及裱花的样式

public abstract class Cake {final void make() {makeStart();//logmakingCakeGerm();//做蛋糕胚makingCream();//制作奶油wipeCakeGerm();//抹蛋糕胚piping();//裱花makeFinish();//log}private void makeStart() {System.out.println("make start");}private void makingCakeGerm() {System.out.println("制作蛋糕胚");}protected abstract void makingCream();//内容不共通的方法,留在子类实现private void wipeCakeGerm() {System.out.println("将奶油抹到蛋糕胚上");}protected abstract void piping();//内容不共通的方法,留在子类实现private void makeFinish() {System.out.println("make finish");}}

子类实现蛋糕A蛋糕B

public class Cake_A extends Cake {@Overridepublic void makingCream() {System.out.println("植物奶油 抹茶味");}@Overridepublic void piping() {System.out.println("裱花八朵");}
}/******************************************/public class Cake_B extends Cake {@Overridepublic void makingCream() {System.out.println("动物奶油 巧克力味");}@Overridepublic void piping() {System.out.println("裱个生日快乐");}
}

最后Main类执行:

public class Test{public static void main(String[] args){Cake_A a = new Cake_A();Cake_B b = new Cake_B();a.make(); System.out.println("******************");b.make(); }
}

看一下输出结果:

I/System.out: make start
I/System.out: 制作蛋糕胚
I/System.out: 植物奶油 抹茶味
I/System.out: 将奶油抹到蛋糕胚上
I/System.out: 裱花八朵
I/System.out: make finish
I/System.out: ******************
I/System.out: make start
I/System.out: 制作蛋糕胚
I/System.out: 动物奶油 巧克力味
I/System.out: 将奶油抹到蛋糕胚上
I/System.out: 裱个生日快乐
I/System.out: make finish

上述示例就是模板方法的一个实际使用模型。

总结一下优缺点:

优点:

  • 复用性增强,可读性增强将相同部分的代码放在抽象的父类中,部分实现代码在子类中完成
  • 扩展性增强,通过增加子类来设计新的逻辑,一子类对应一套逻辑
  • 遵守了开闭原则,并通过父类调用其子类的扩展方法实现了反向控制

缺点:

     缺点很显然了,你如果拥有海量的蛋糕设计方法,那你就要实现非常多个子类

应用场景:

在逻辑设计时,将不变(也称共通)的逻辑做在父类中,变化的逻辑以抽象方法的形式在父类中,由子类后续继承实现,且后续的改动和拓展均应由子类完成,维持父类不动

-------------------------------解答时间----------------------------------

问:有人会说Test类应该是父类型引用指向子类对象,然后调用父类型变量中的.make()方法吧?

答:显然没必要,这种设计模式的核心思想不在多态上,向上转型诚然也可以实现,但是模板方法的核心在于抽象步骤,公共复用,所以用不用向上转型影响不大

问:有人学习了策略模式后会感到疑惑,这和模板方法也太像了吧?

答:不要怀疑,确实很像!区别就是策略模式用接口实现逻辑的扩展性,而模板方法用继承的方式完成逻辑的扩展性

---------------------------------------------------------------------------

虽然到这里就是模板方法的大体设计思想了,但是这还不算完,模板方法还有一个punchline

“钩子方法”

提问3:现在你突然着急吃蛋糕了,那怎么办?砍步骤呗,最后那个裱花不要了,这个时候代码怎么写?

父类增加判断默认执行裱花,子类增加标记位isPipe,并提供设定标记位的函数isPipe(),这个函数就是钩子方法

public abstract class Cake {final void make() {makeStart();//logmakingCakeGerm();//做蛋糕胚makingCream();//制作奶油wipeCakeGerm();//抹蛋糕胚if (isPipe()) {piping();//裱花}makeFinish();//log}......//父类增加一个方法用来判定标记位置,这里默认用true,后续子类拓展protected boolean isPipe() {return true;}
}
public class Cake_C extends Cake {private boolean isPipe = true;//是否裱花的标记位@Overridepublic void makingCream() {System.out.println("动物奶油 巧克力味");}@Overridepublic void piping() {System.out.println("裱个生日快乐");}@Overridepublic boolean isPipe() {return this.isPipe;}public void setPipe(boolean isPipe) {//设定标记位this.isPipe = isPipe;}
}

最后我们更改一下Test类的写法:

public class Test{public static void main(String[] args){Cake_A a = new Cake_A();Cake_C c = new Cake_C();c.setPipe(false);a.make(); System.out.println("******************");c.make(); }
}

我们在Test类中设定蛋糕C不裱花执行,这回蛋糕C没有裱花就做完了。

细想,父类其实并没有变,依然能够完整执行,但是却能靠子类的方法返回值,来改变最终的执行结果,这便是模板方法的点睛之笔了,而这篇日记到此也就完整了。

Java设计模式之——模板方法相关推荐

  1. Java设计模式之模板方法模式(UML类图分析+代码详解)

    大家好,我是一名在算法之路上不断前进的小小程序猿!体会算法之美,领悟算法的智慧~ 希望各位博友走过路过可以给我点个免费的赞,你们的支持是我不断前进的动力!! 加油吧!未来可期!! 本文将介绍java设 ...

  2. Java 设计模式之模板方法模式

    一.了解模板方法模式 1.1 什么是模板方法模式 模板方法模式 Template Method Parrern)在一个方法中定义了一个算法的骨架,而将一些步骤延迟到子类中.模板方法使得子类可以在不改变 ...

  3. Java设计模式之模板方法设计模式(银行计息案例)

    不知道为什么,这几天对Java中的设计模式非常感兴趣,恰巧呢这几天公司的开发任务还不算太多,趁着有时间昨天又把模板方法模式深入学习了一下,做了一个客户在不同银行计息的小案例,感触颇深,今天给各位分享一 ...

  4. JAVA设计模式之--模板方法模式

    序言 在现实生活中,很多事情都包含几个实现步骤,例如请客吃饭,无论吃什么,一般都包含点单.吃东西.买单等几个步骤,通常情况下这几个步骤的次序是:点单 --> 吃东西 --> 买单.在这三个 ...

  5. JAVA设计模式什么鬼(模板方法)——作者:凸凹里歐

    面向对象,是对事物属性与行为的封装,方法,指的就是行为.模板方法,显而易见是说某个方法充当了模板的作用,其充分利用了抽象类虚实结合的特性,虚部抽象预留,实部固定延续,以达到将某种固有行为延续至子类的目 ...

  6. java设计模式之模板方法

    所谓的模板方法其实就是按照一套模板下来的,就像小时候做数学题,按照一定的套路做出来 . 1.建立一个抽象方法是模板具体的步骤如下. package templatemethod; public abs ...

  7. 从西天取经的九九八十一难来看Java设计模式:模板方法模式

    模板方法模式 示例 模板方法模式 定义 意图 主要解决问题 适用场景 优缺点 西天取经的九九八十一难 示例 当我们设计一个类时,我们能明确它对外提供的某个方法的内部执行步骤, 但一些步骤,不同的子类有 ...

  8. java设计模式 之 模板方法模式

    1.模板方法模式的定义: 定义一个操作中的算法的框架,而将一些步骤延迟到子类中.使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤. 2.模板方法模式的优点: ● 封装不变部分,扩展可变部 ...

  9. Java设计模式之——模板方法模式

    Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template Me ...

最新文章

  1. 如何在Linux使用Eclipse + CDT开发C/C++程序?
  2. oracle 查看 用户,用户权限,用户表空间,用户默认表空间
  3. 视频会议场景下的弱网优化
  4. Go Web:HttpRouter路由
  5. 边缘检测后去除噪点_Street Lanes Finder - 检测自动驾驶汽车的车道
  6. linux 反汇编运行时代码段,linux内核学习之一 简单c语言反汇编(示例代码)
  7. 深入浅出聊优化:从Draw Calls到GC(转)
  8. linux HUSTOJ 一些页面修改
  9. 公达 TP-POS58G 打印机驱动
  10. 图像采集——OV5640摄像头简介、硬件电路及上电控制的Verilog代码实现并进行modelsim仿真
  11. 研发岗位OKR的设计与激励 - 管理角度(附部分岗位样例)
  12. HSI彩色图像空间滤波
  13. 脉脉热帖:数仓真的是太无聊了...
  14. Android 4.0 SDK新特性
  15. 【QGIS入门实战精品教程】4.8:QGIS如何下载SRTM数字高程模型DEM?
  16. 1062lcd在dxp哪个库_Protel DXP 自带常用元件库路径
  17. 使用 iview 实现PC端生成推广海报与二维码并下载的功能,基于iview Modal 对话框 与 Carousel 走马灯组件实现
  18. 微软为Windows8平板所配备的键鼠套装
  19. 图的深度优先搜索及拓扑排序
  20. 深度学习目标检测数据VisDrone2019(to yolo / voc / coco)---MMDetection数据篇

热门文章

  1. js做的一个猜数字小游戏
  2. GlobalSign和DigiCert对比
  3. c++ 与 数据结构 实现 《校园路径导航系统》
  4. 怎么修改图片的kb大小?如何缩小照片kb?
  5. Data-driven methods for solving algebra word problems论文阅读
  6. windows7彻底删除流氓软件的操作方法
  7. google语音搜索识别API【转载】
  8. TensorFlow对象检测-1.0和2.0:训练,导出,优化(TensorRT),推断(Jetson Nano)
  9. 一辈子不用考试?你可能是个假程序员,小心成杠精
  10. Chrome浏览器快速切换DOH DNS