1. 意图(Intent)

定义算法框架,并将一些步骤的实现延迟到子类。
通过模板方法,子类可以重新定义算法的某些步骤,而不用改变算法的结构。

2. 类图(Class Diagram)

ac6a794b-68c0-486c-902f-8d988eee5766.png

3. 实现(Implementation)

I 基本模板

通常会有一个抽象类:[ AbstractClass ]

  1. public abstract class AbstractTemplate {
  2. // 这就是模板方法
  3. public void templateMethod() {
  4. init();
  5. apply(); // 这个是重点
  6. end(); // 可以作为钩子方法
  7. }
  8. protected void init() {
  9. System.out.println("init 抽象层已经实现,子类也可以选择覆写");
  10. }
  11. // 留给子类实现
  12. protected abstract void apply();
  13. protected void end() {
  14. System.out.println("end 抽象层已经实现,子类也可以选择覆写");
  15. }
  16. }

模板方法中调用了 3 个方法,其中 apply() 是抽象方法,子类必须实现它,其实模板方法中有几个抽象方法完全是自由的,我们也可以将三个方法都设置为抽象方法,让子类来实现。也就是说,模板方法只负责定义第一步应该要做什么,第二步应该做什么,第三步应该做什么,至于怎么做,由子类来实现。
我们写一个实现类:[ ConcreteClass ]

  1. public class ConcreteTemplate extends AbstractTemplate {
  2. public void apply() {
  3. System.out.println("子类实现抽象方法 apply");
  4. }
  5. @Override
  6. public void end() {
  7. System.out.println("我们可以把 method3 当做钩子方法来使用,需要的时候覆写就可以了");
  8. }
  9. }

客户端调用演示:

  1. public static void main(String[] args) {
  2. AbstractTemplate template = new ConcreteTemplate();
  3. // 调用模板方法
  4. template.templateMethod();
  5. }

II 泡茶案例

冲咖啡和冲茶都有类似的流程,但是某些步骤会有点不一样,要求复用那些相同步骤的代码。

image.png

咖啡因饮料抽象类 [ AbstractClass ]

  1. public abstract class CaffeineBeverage {
  2. // 定义的模板方法步骤
  3. final void prepareRecipe() {
  4. boilWater(); // 烧水 * 相同
  5. brew(); // 酿造
  6. pourInCup(); // 倒入杯中 * 相同
  7. addCondiments(); // 添加调味品
  8. }
  9. abstract void brew();
  10. abstract void addCondiments();
  11. void boilWater() {
  12. System.out.println("boilWater");
  13. }
  14. void pourInCup() {
  15. System.out.println("pourInCup");
  16. }
  17. }

[ ConcreteClass ]

咖啡具体类

  1. public class Coffee extends CaffeineBeverage {
  2. @Override
  3. void brew() {
  4. System.out.println("Coffee.brew Coffee Grinds"); // 冲泡咖啡粉
  5. }
  6. @Override
  7. void addCondiments() {
  8. System.out.println("Coffee.addCondiments<Sugar,Milk>");
  9. }
  10. }

茶水具体类

  1. public class Tea extends CaffeineBeverage {
  2. @Override
  3. void brew() {
  4. System.out.println("Tea.brew.SteepTeabag"); // 悬挂茶包
  5. }
  6. @Override
  7. void addCondiments() {
  8. System.out.println("Tea.addCondiments<Lemon>");
  9. }
  10. }

客户端演示:

  1. public class Client {
  2. public static void main(String[] args) {
  3. CaffeineBeverage caffeineBeverage = new Coffee();
  4. caffeineBeverage.prepareRecipe();
  5. System.out.println("-----------");
  6. caffeineBeverage = new Tea();
  7. caffeineBeverage.prepareRecipe();
  8. }
  9. }

输出:

  1. boilWater
  2. Coffee.brew Coffee Grinds
  3. pourInCup
  4. Coffee.addCondiments<Sugar,Milk>
  5. -----------
  6. boilWater
  7. Tea.brew.SteepTeabag
  8. pourInCup
  9. Tea.addCondiments<Lemon>

4. JDK

  • java.util.Collections#sort()
  • java.io.InputStream#skip()
  • java.io.InputStream#read()
  • java.util.AbstractList#indexOf()