1. 意图(Intent)
定义算法框架,并将一些步骤的实现延迟到子类。
通过模板方法,子类可以重新定义算法的某些步骤,而不用改变算法的结构。
2. 类图(Class Diagram)
3. 实现(Implementation)
I 基本模板
通常会有一个抽象类:[ AbstractClass ]
public abstract class AbstractTemplate {// 这就是模板方法public void templateMethod() {init();apply(); // 这个是重点end(); // 可以作为钩子方法}protected void init() {System.out.println("init 抽象层已经实现,子类也可以选择覆写");}// 留给子类实现protected abstract void apply();protected void end() {System.out.println("end 抽象层已经实现,子类也可以选择覆写");}}
模板方法中调用了 3 个方法,其中 apply() 是抽象方法,子类必须实现它,其实模板方法中有几个抽象方法完全是自由的,我们也可以将三个方法都设置为抽象方法,让子类来实现。也就是说,模板方法只负责定义第一步应该要做什么,第二步应该做什么,第三步应该做什么,至于怎么做,由子类来实现。
我们写一个实现类:[ ConcreteClass ]
public class ConcreteTemplate extends AbstractTemplate {public void apply() {System.out.println("子类实现抽象方法 apply");}@Overridepublic void end() {System.out.println("我们可以把 method3 当做钩子方法来使用,需要的时候覆写就可以了");}}
客户端调用演示:
public static void main(String[] args) {AbstractTemplate template = new ConcreteTemplate();// 调用模板方法template.templateMethod();}
II 泡茶案例
冲咖啡和冲茶都有类似的流程,但是某些步骤会有点不一样,要求复用那些相同步骤的代码。

咖啡因饮料抽象类 [ AbstractClass ]
public abstract class CaffeineBeverage {// 定义的模板方法步骤final void prepareRecipe() {boilWater(); // 烧水 * 相同brew(); // 酿造pourInCup(); // 倒入杯中 * 相同addCondiments(); // 添加调味品}abstract void brew();abstract void addCondiments();void boilWater() {System.out.println("boilWater");}void pourInCup() {System.out.println("pourInCup");}}
[ ConcreteClass ]
咖啡具体类
public class Coffee extends CaffeineBeverage {@Overridevoid brew() {System.out.println("Coffee.brew Coffee Grinds"); // 冲泡咖啡粉}@Overridevoid addCondiments() {System.out.println("Coffee.addCondiments<Sugar,Milk>");}}
茶水具体类
public class Tea extends CaffeineBeverage {@Overridevoid brew() {System.out.println("Tea.brew.SteepTeabag"); // 悬挂茶包}@Overridevoid addCondiments() {System.out.println("Tea.addCondiments<Lemon>");}}
客户端演示:
public class Client {public static void main(String[] args) {CaffeineBeverage caffeineBeverage = new Coffee();caffeineBeverage.prepareRecipe();System.out.println("-----------");caffeineBeverage = new Tea();caffeineBeverage.prepareRecipe();}}
输出:
boilWaterCoffee.brew Coffee GrindspourInCupCoffee.addCondiments<Sugar,Milk>-----------boilWaterTea.brew.SteepTeabagpourInCupTea.addCondiments<Lemon>
4. JDK
- java.util.Collections#sort()
- java.io.InputStream#skip()
- java.io.InputStream#read()
- java.util.AbstractList#indexOf()
