定义

模板方法模式在一个方法中定义一个算法骨架,并将某些步骤推迟到子类中实现。模板方法模式可以让子类在不改变算法整体结构的情况下,重新定义算法中的某些步骤。

简单来说模板方法定义了一套流程,流程中有哪些操作,操作的具体顺序是什么。而操作的具体实现则交给其子类去实现,模板方法不需要关心。

示例

现有需要对接支付宝和微信支付,部分方法是公用的,另外的需要不同的实现。这里可以使用模板方法,支付流程简单定义为

  • 打开App
  • 输入支付金额 (公用)
  • 用户校验
  • 显示支付结果

AbstractPaymentProcess

public abstract class AbstractPaymentProcess {

    /**
     * 支付流程
     */
    public void pay(double amount) {
        launchApp();
        inputMoney(amount);
        inputPassword();
        faceId();
        paymentResult();
    }

    /**
     * 打开App
     */
    protected abstract void launchApp();

    /**
     * 输入支付金额
     * @param amount 支付金额
     */
    private final void inputMoney(double amount) {
        System.out.println("当前待支付金额: " + amount + "元。");
    }

    /**
     * 输入密码
     */
    protected void inputPassword() {}

    /**
     * 面部识别支付
     */
    protected void faceId() {}

    /**
     * 支付结果
     */
    protected abstract void paymentResult();

}

打开App和显示支付结果为子类必须实现的方法,使用abstract修饰。
输入密码校验还是面部识别,选择一种实现即可,不定义为抽象方法。
输入支付金额为公用方法,已经内部实现。

WeChatPayment

public class WeChatPayment extends AbstractPaymentProcess {

    @Override
    protected void launchApp() {
        System.out.println("打开微信");
    }

    @Override
    protected void inputPassword() {
        System.out.println("-----微信支付界面-----");
        System.out.println("密码输入中...");
        System.out.println("密码校验中...");
    }

    @Override
    protected void paymentResult() {

        boolean success = new Random().nextBoolean();
        System.out.println("微信支付结果:");
        if (success) {
            System.out.println("支付成功!");
        } else {
            System.out.println("支付失败!");
        }
    }
}

AliPayment

public class AliPayment extends AbstractPaymentProcess {

    @Override
    protected void launchApp() {
        System.out.println("打开支付宝");
    }

    @Override
    protected void faceId() {
        System.out.println("-----支付宝界面-----");
        System.out.println("面容ID识别中...");
    }

    @Override
    protected void paymentResult() {

        boolean success = new Random().nextBoolean();
        System.out.println("支付宝支付结果:");
        if (success) {
            System.out.println("支付成功!");
        } else {
            System.out.println("支付失败!");
        }
    }
}

TestTemplateMethod

@Test
public void test() {

    AbstractPaymentProcess aliPay = new AliPayment();
    aliPay.pay(12);

    System.out.println("---------------------------------");

    AbstractPaymentProcess weChatPay = new WeChatPayment();
    weChatPay.pay(6);

}

输出结果

打开支付宝
当前待支付金额: 12.0元。
-----支付宝界面-----
面容ID识别中...
支付宝支付结果:
支付成功!
---------------------------------
打开微信
当前待支付金额: 6.0元。
-----微信支付界面-----
密码输入中...
密码校验中...
微信支付结果:
支付失败!

可以看到,模板方法的优点是提升了代码的复用性和可拓展性。增加一种实现只需要增加一个子类,根据自己的业务去实现抽象方法即可。
缺点是后续的话类的数量可能会很多,不便于维护,如果修改了抽象类,可能需要修改的类数量很多。

总结

模板方法的核心思想是:父类定义骨架子类实现某些细节

参考资料

模板方法 (宝,我输液了,输的想你的夜)
模板方法 - 廖雪峰的官方网站

Q.E.D.


The best thing you can do at work hard.