CS-Notes全部笔记在阅读器中打开

模板方法(Template Method)

意图

定义算法框架,并将一些步骤的实现延迟到子类。

通过模板方法,子类可以重新定义算法的某些步骤,而不用改变算法的结构。

类图

类图的配图

实现

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

实现的配图

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");
    }
}
public class Coffee extends CaffeineBeverage {
    @Override
    void brew() {
        System.out.println("Coffee.brew");
    }

    @Override
    void addCondiments() {
        System.out.println("Coffee.addCondiments");
    }
}
public class Tea extends CaffeineBeverage {
    @Override
    void brew() {
        System.out.println("Tea.brew");
    }

    @Override
    void addCondiments() {
        System.out.println("Tea.addCondiments");
    }
}
public class Client {
    public static void main(String[] args) {
        CaffeineBeverage caffeineBeverage = new Coffee();
        caffeineBeverage.prepareRecipe();
        System.out.println("-----------");
        caffeineBeverage = new Tea();
        caffeineBeverage.prepareRecipe();
    }
}
boilWater
Coffee.brew
pourInCup
Coffee.addCondiments
-----------
boilWater
Tea.brew
pourInCup
Tea.addCondiments

prepareRecipe() 用 final 修饰,子类不能改变步骤和顺序,必须实现的只有 brew() 和 addCondiments() 这两个抽象步骤。

模板方法通过继承固定流程、替换其中的步骤,策略通过组合替换整个算法。

JDK 中的应用

InputStream#read(byte[], int, int) 是一个模板方法:它循环调用抽象的 read() 逐个读取字节,子类只实现读一个字节的 read() 就能批量读取。AQS(AbstractQueuedSynchronizer)也是这样:acquire() 固定了获取失败后排队、挂起的流程,子类(例如 ReentrantLock 内部的 FairSync、NonfairSync)只实现 tryAcquire(),见 AQS。

参考资料

在阅读器中可以用目录和搜索、切换深色模式、练习这篇笔记中的面试题:打开《设计模式 - 模板方法》