模版方法模式(模版模式)初体验和总结
2021/8/15 6:37:00
本文主要是介绍模版方法模式(模版模式)初体验和总结,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
模版方法模式,也叫做模版模式,是一种行为型模式:
-
- 定义一个算法骨架,并允许子类为为其中的一个或者多个步骤提供实现。
-
- 模版方法使得子类在不改变算法结构的情况下,重新定义算法的某些步骤。可以使用钩子方法,让子类去实现细节,钩子可以让子类有能力为其抽象类做一些决定。
-
- 模版模式可以在抽象父类定义统一的方法,减少代码重复。
模版方法模式举例
比如制作饮料的场景:泡咖啡和泡蜂蜜绿茶
- 泡咖啡: 1. 先要烧开水 2. 冲泡咖啡 3. 将咖啡倒入到杯子中 4. 加入糖和牛奶
- 泡蜂蜜绿茶: 1. 先要烧开水 2. 浸泡茶叶 3. 将茶水倒入杯子中 4. 放入少量蜂蜜
发现他们有几个动作是一样的,比如都要烧开水,都要冲泡,都要倒入杯子中,都要放入一些调味品,那这几个动作就可以抽象,用模版模式来实现
1. 首先创建个抽象类,定义类: AbstractMakeDrinkHandler ,制作饮料的抽象类
/** * 制作饮料的抽象类 */ abstract class AbstractMakeDrinkHandler { final void makeDrinkStart() { //1.把水煮沸 boilWater(); //2.独特的浸泡方法 soakMaterial(); //3.倒入茶杯 pourTeacup(); //4.加入调味品 addSeasoning(); } /** * 烧开水方法 */ void boilWater() { System.out.println("开始烧水"); } /** * 抽象的冲泡方法,由子类实现细节 */ protected abstract void soakMaterial(); /** * 倒入茶杯的方法 */ void pourTeacup() { System.out.println("将饮料倒入杯子中"); } /** * 加入调味品的方法,由子类实现细节 */ protected abstract void addSeasoning(); }
这里由于烧开水方法和倒入茶杯的方法是一样的,可以抽象成公共的逻辑放在父类中,冲泡方法和加入调味品的方法定义为抽象方法,由子类来实现具体细节
2. 创建泡咖啡类和泡蜂蜜绿茶类
制作咖啡类
/** * 制作咖啡类 */ public class MarkCoffeeHandler extends AbstractMakeDrinkHandler { @Override protected void soakMaterial() { System.out.println("用沸水冲泡咖啡,然后用勺子采用360度缓慢旋转2分钟"); } @Override protected void addSeasoning() { System.out.println("咖啡里加点糖和牛奶"); } }
制作绿茶类
/** * 制作绿茶类 */ public class MarkTeaHandler extends AbstractMakeDrinkHandler { @Override protected void soakMaterial() { System.out.println("用沸水浸泡茶叶,等茶叶慢慢落下,浸泡2分钟"); } @Override protected void addSeasoning() { System.out.println("茶里加点蜂蜜"); } }
main方法
public class MainClass { public static void main(String[] args) { //制作咖啡 MarkCoffeeHandler coffeeHandler = new MarkCoffeeHandler(); coffeeHandler.makeDrinkStart(); System.out.println("======================="); //制作绿茶 MarkTeaHandler teaHandler = new MarkTeaHandler(); teaHandler.makeDrinkStart(); } }
执行,控制台输出结果
开始烧水 用沸水冲泡咖啡,然后用勺子采用360度缓慢旋转2分钟 将饮料倒入杯子中 咖啡里加点糖和牛奶 ======================= 开始烧水 用沸水浸泡茶叶,等茶叶慢慢落下,浸泡2分钟 将饮料倒入杯子中 茶里加点蜂蜜
这里会发现,父类很好的约束了算法的框架,子类对细节进行了实现,父类也把复用的代码进行了抽象
扩展点:
-
- 将饮料倒入杯子中,我想知道具体倒入的是什么饮料,如何知道呢?
-
- 冲泡的时候,根据客户需要,可能是热饮料,也可能是凉的饮料,热的饮料要玻璃杯装,凉的饮料可以用纸杯装,这个如何实现?
这时候,就需要用到钩子方法,由子类来决定要不要继承,来修改父类的行为。更改后的代码如下:
/** * 制作饮料的抽象类 */ abstract class AbstractMakeDrinkHandler { final void makeDrinkStart() { //1.把水煮沸 boilWater(); //2.用沸水浸泡茶/冲泡咖啡 soakMaterial(); //3.倒入茶杯 pourTeacup(); //4.加入调料 addSeasoning(); } /** * 烧开水方法 */ void boilWater() { System.out.println("开始烧水"); } /** * 抽象的冲泡方法,由子类实现细节 */ protected abstract void soakMaterial(); /** * 倒入茶杯的方法 */ void pourTeacup() { if (hotDrink()) { System.out.println("热饮料需要准备玻璃杯"); } else { System.out.println("准备纸杯"); } System.out.println("将" + getDrinkName() + "倒入杯子中"); } /** * 加入调味品的方法,由子类实现细节 */ protected abstract void addSeasoning(); /** * 钩子方法,返回饮料的类别 * @return */ public String getDrinkName() { return "饮料"; } /** * 钩子方法,返回是冷饮还是热饮 * @return */ public boolean hotDrink() { return false; } }
制作咖啡类 和制作绿茶类
/** * 制作咖啡类 */ public class MarkCoffeeHandler extends AbstractMakeDrinkHandler { private String drinkName; private boolean hotDrink; public MarkCoffeeHandler(boolean hotDrink) { this.hotDrink = hotDrink; this.drinkName = "咖啡"; } @Override protected void soakMaterial() { System.out.println("用沸水冲泡咖啡,然后用勺子采用360度缓慢旋转2分钟"); } @Override protected void addSeasoning() { System.out.println("咖啡里加点糖和牛奶"); } @Override public boolean hotDrink() { return this.hotDrink; } @Override public String getDrinkName() { return this.drinkName; } }
/** * 制作绿茶类 */ public class MarkTeaHandler extends AbstractMakeDrinkHandler { private String drinkName; private boolean hotDrink; public MarkTeaHandler(boolean hotDrink) { this.hotDrink = hotDrink; this.drinkName = "绿茶"; } @Override protected void soakMaterial() { System.out.println("用沸水浸泡茶叶,等茶叶慢慢落下,浸泡2分钟"); } @Override protected void addSeasoning() { System.out.println("茶里加点蜂蜜"); } @Override public String getDrinkName() { return this.drinkName; } @Override public boolean hotDrink() { return this.hotDrink; } }
main方法
public class MainClass { public static void main(String[] args) { //制作咖啡 MarkCoffeeHandler coffeeHandler = new MarkCoffeeHandler(true); coffeeHandler.makeDrinkStart(); System.out.println("======================="); //制作绿茶 MarkTeaHandler teaHandler = new MarkTeaHandler(false); teaHandler.makeDrinkStart(); } }
执行方法后控制台输出
开始烧水 用沸水冲泡咖啡,然后用勺子采用360度缓慢旋转2分钟 热饮料需要准备玻璃杯 将咖啡倒入杯子中 咖啡里加点糖和牛奶 ======================= 开始烧水 用沸水浸泡茶叶,等茶叶慢慢落下,浸泡2分钟 准备纸杯 将绿茶倒入杯子中 茶里加点蜂蜜
发现子类通过钩子方法,很好的改变了父类冲泡方法的细节,为是准备玻璃杯还是纸杯提供了决定
关联的类图如下
模版方法模式优点:
-
- 利用模版方法模式把相同逻辑的代码抽象到抽象父类中,提高代码复用性,符合开闭原则
-
- 定义一系列算法框架,子类在不改变算法框架的情况下,扩展新的行为,并且可以通过钩子方法,对父类一些
算法实现细节做出决定。
- 定义一系列算法框架,子类在不改变算法框架的情况下,扩展新的行为,并且可以通过钩子方法,对父类一些
模版方法模式缺点:
-
- 类的增加,系统增加复杂度
-
- 继承关系自身缺点,父类添加新的方法,所有子类都要改一遍,依赖关系比组合更强
模版方法在java 中的使用:
-
- jdbcTemplate 类,里面定义了从加载驱动,封装了所有jdbc操作,包括1.建立连接,2.创建语句集 3. 执行语句集 4. 返回结果集 5. 关闭连接
-
- AbstractList 类, 里面定义了通用的 indexOf , lastIndexOf,equals,hashCode()方法,但是get是一个抽象方法,需要通过子类来实现。
/** * {@inheritDoc} * * @throws IndexOutOfBoundsException {@inheritDoc} */ abstract public E get(int index);
add 方法,addAll 方法 是钩子方法,由子类决定要不要实现,比如ArrayList ,LinkedList 都有具体的实现
public boolean add(E e) { add(size(), e); return true; } public boolean addAll(int index, Collection<? extends E> c) { rangeCheckForAdd(index); boolean modified = false; for (E e : c) { add(index++, e); modified = true; } return modified; }
-
- HttpServlet 类 , 比如 doGet ,doPost,doPut ,service 等都是模版方法的抽象实现,由子类去实现细节
这篇关于模版方法模式(模版模式)初体验和总结的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2025-01-11cursor试用出现:Too many free trial accounts used on this machine 的解决方法
- 2025-01-11百万架构师第十四课:源码分析:Spring 源码分析:深入分析IOC那些鲜为人知的细节|JavaGuide
- 2025-01-11不得不了解的高效AI办公工具API
- 2025-01-102025 蛇年,J 人直播带货内容审核团队必备的办公软件有哪 6 款?
- 2025-01-10高效运营背后的支柱:文档管理优化指南
- 2025-01-10年末压力山大?试试优化你的文档管理
- 2025-01-10跨部门协作中的进度追踪重要性解析
- 2025-01-10总结 JavaScript 中的变体函数调用方式
- 2025-01-10HR团队如何通过数据驱动提升管理效率?6个策略
- 2025-01-10WBS实战指南:如何一步步构建高效项目管理框架?