行为模式之模板方法模式

Posted by Night Field's Blog on May 30, 2020

1 概述

模板方法模式(Template Method Pattern)是一种很常见的行为模式。在超类/抽象类中创建一个模板方法,方法中定义一个算法步骤或框架,让子类在不修改主结构的情况下,重写其中的子步骤。

2 模板方法模式

假如存在一系列对象的方法,他们的步骤是大体一致的,区别只是其中的一个子步骤。这种情况会导致大量重复冗余的代码,当公共部分需要改变时,不得不修改所有相关的对象。如果用模版方法模式改造,可以简化逻辑:将其中不变的部分抽离出来,作为一个模板方法,然后让子类只实现差异化的部分代码。 比如,前面举过的例子中,网上购物结算可以有多种途径,支付宝微信等等,所以对于“网上购物”,运用模板方法模式的思想,便可以将挑选商品加入购物车提交订单支付结算这几个步骤,定义成模板方法。其中,前面三个步骤是通用的,最后一个方法,留给子类根据不同的支付方式去实现自己的逻辑。 一般情况下,模板方法应该定义为final,因为它包含了算法的框架,不应该被子类覆盖重写。类似的,需要子类重写的差异化方法,需要定义为abstract

3 案例

看一个案例加深理解。做披萨的一般顺序是:做披萨皮,加浇头,烘焙。披萨是什么口味,完全看浇头是什么,所以,我们可以用模版方法模式来“制作披萨”:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public abstract class PizzaCook {
    public final void bakePizza() {
        processCrust();
        processTopping();
        bake();
        System.out.println("Pizza is now baked!!!");
    }
    private void processCrust() {
        System.out.println("Crust is ready...");
    }
    private void bake() {
        System.out.println("Putting the pizza to oven...");
    };
    protected abstract void processTopping();

}
public class FruitPizzaCook extends PizzaCook {
    @Override
    protected void processTopping() {
        System.out.println("Putting some fruit on the Pizza...");
    }
}
public class BaconPizzaCook extends PizzaCook {
    @Override
    protected void processTopping() {
        System.out.println("Putting the bacon on the Pizza...");
    }
}

public class Test {
    public static void main(String[] args) {
        PizzaCook fruitPizzaCook = new FruitPizzaCook();
        fruitPizzaCook.bakePizza();
        System.out.println("--------------");
        PizzaCook baconPizzaCook = new BaconPizzaCook();
        baconPizzaCook.bakePizza();
    }
}

输出:

1
2
3
4
5
6
7
8
9
Crust is ready...
Putting some fruit on the Pizza...
Putting the pizza to oven...
Pizza is now baked!!!
--------------
Crust is ready...
Putting the bacon on the Pizza...
Putting the pizza to oven...
Pizza is now baked!!!

父类中定义了披萨的制作步骤,作为子类,只需要实现processTopping()方法。模板方法模式省去了很多重复代码,方便了代码重用。当公共部分(processCrust()/bake)需要改动时,只需要改动父类即可。 JDK中,所有的List都继承了AbstractList,所有的Set都继承了AbstractSet,所有的Map都继承了AbstractMap模板方法模式在这三个类中得到了很好的运用。

4 总结

模板方法模式通过将方法的步骤抽象分离,封装不变部分,扩展可变部分,减少了冗余代码,方便了维护。

文中例子的github地址