在模板模式中,定义了一个公开的执行模板的方法,字类可以按照需自己实现方法,但是它们的调用方法是必须要按照抽象类的方式来进行。
意图:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
主要解决:一些方法通用,却在每一个子类都重新写了这一方法。
何时使用:有一些通用的方法。
如何解决:将这些通用算法抽象出来。
优点: 1、封装不变部分,扩展可变部分。 2、提取公共代码,便于维护。 3、行为由父类控制,子类实现。
缺点:每一个不同的实现都需要一个子类来实现,导致类的个数增加,使得系统更加庞大。
使用场景: 1、有多个子类共有的方法,且逻辑相同。 2、重要的、复杂的方法,可以考虑作为模板方法。
注意事项:为防止恶意操作,一般模板方法都加上 final 关键词。
举个例子:就以我自己每天上班去公司为例:首先我要起床、然后洗漱、乘交通工具去公司、吃早饭、最后打卡;因为工作日每天都差不多,最多就是早饭吃不吃。
下面是简单的类图:
要实现模板模式主要分以下几个步骤:
- 定义一个模板抽象类,定义模板方法
- 字类实现暴露出来的一些通用方法
- 客户端调用模板方法
1、定义一个模板抽象类,定义模板方法
package com.dongl.templatemethod; /** * 定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。 * * 建立一个码农模板 就以我个人而言 正常的工作日大部分的日常生活都是差不多的 所以可以用模板化来建立 * 这里就举例一个 从起床到公司的模板 */ public abstract class CodeTheAgriculture { /** * 一些方法通用,却在每一个子类都重新写了这一方法 * 其中可由字类实现的方法 定义为protected */ //醒了起床 protected abstract void wakeUp(); //洗漱 protected abstract void wash(); //成交通工具到公司楼下 protected abstract void byVehicle(); //吃早饭 protected abstract void breakfast(); //上楼打卡 protected abstract void punchCard(); /** * 为防止恶意操作,一般模板方法都加上 final 关键词。 */ final public void goToWork(){ this.wakeUp(); this.wash(); this.byVehicle(); if (this.isBreakfast()){ this.breakfast(); } this.punchCard(); } /** * 加一个钩子方法 默认为true 每天都吃早餐 * 这里因为每天吃不吃早饭主要取决于打卡来不来得及 如果时间紧 就不吃 来得及 就吃 * @return */ protected boolean isBreakfast(){ return true; } }
2、子类实现暴露出来的一些通用方法
今天:
package com.dongl.templatemethod; public class Today extends CodeTheAgriculture { private boolean breakfastFlag = true; //是否要吃早饭 @Override protected void wakeUp() { System.out.println("今天的我醒了-----------"); } @Override protected void wash() { System.out.println("今天的我洗漱了----------"); } @Override protected void byVehicle() { System.out.println("今天骑共享单车去的公司----------"); } @Override protected void breakfast() { System.out.println("今天吃早饭了---------------------"); } @Override protected void punchCard() { System.out.println("今天我打卡了------------------"); } @Override protected boolean isBreakfast() { return this.breakfastFlag; } /** * 自定义是否要吃早饭 * @param breakfast */ public void setBreakfastFlag(boolean breakfast) { this.breakfastFlag = breakfast; } }
昨天:
package com.dongl.templatemethod; public class Yesterday extends CodeTheAgriculture { private boolean breakfastFlag = true; //是否要吃早饭 @Override protected void wakeUp() { System.out.println("昨天的我醒了-----------"); } @Override protected void wash() { System.out.println("昨天的我洗漱了----------"); } @Override protected void byVehicle() { System.out.println("昨天坐公交车去的公司----------"); } @Override protected void breakfast() { System.out.println("昨天吃早饭了---------------------"); } @Override protected void punchCard() { System.out.println("昨天我打卡了------------------"); } @Override protected boolean isBreakfast() { return false; } /** * 自定义是否要吃早饭 * @param breakfast */ public void setBreakfastFlag(boolean breakfast) { this.breakfastFlag = breakfast; } }
3、客户端调用模板方法
package com.dongl.templatemethod; public class Client { public static void main(String[] args) { Today today = new Today(); today.setBreakfastFlag(true); today.goToWork(); System.out.println("---------------------------------------------------------"); Yesterday yesterday = new Yesterday(); yesterday.goToWork(); } }