初識設計模式 – 模板方法模式

簡介

在模板方法設計模式(Template Method Design Pattern)中比較重要的兩個概念是 基本方法模板方法

實現具體邏輯步驟的方法可以稱之為基本方法,而把基本方法匯總起來形成一個總算法或總行為的方法稱之為模板方法。

基本方法包括以下幾種類型:

  • 具體方法:在抽象類中聲明,由具體子類實現
  • 抽象方法:在抽象類中已經實現,在具體子類中可以繼承或重寫
  • 鉤子方法:在抽象類中已經實現,包括用於判斷的邏輯方法和需要子類重寫的空方法兩種

典型實現

在模板方法模式中,最重要的就是定義好一個抽象類,並在其中歸納總結出一個模板方法。一般而言,其代碼結構示例如下:

public abstract class AbstractClass {
    // 模板方法
    public void templateMethod() {
        // 一般來說,主要是如何執行基本方法
        concreteMethod();
        abstractMethod();
        hookMethod();
    }

    // 基本方法 - 具體方法
    public void concreteMethod() {
        // 實現代碼
    }

    // 基本方法 - 抽象方法
    public abstract void abstractMethod();

    // 基本方法 - 鉤子方法
    public void hookMethod() {
        // 實現代碼
    }
}

然後,需要定義一個繼承自抽象類的具體子類,並根據業務重寫相應基本方法,其代碼示例如下:

public class ConcreteClass extends AbstractClass {
    // 基本方法 - 抽象方法
    @Override
    public void abstractMethod() {
        // 實現代碼
    }

    // 基本方法 - 鉤子方法
    @Override
    public void hookMethod() {
        // 實現代碼
    }
}

總結

優點

模板方法模式的主要優點如下:

  • 封裝了不變部分,擴展了可變部分
  • 在父類中提取了公共的部分代碼,便於代碼復用
  • 通過子類覆蓋父類的鉤子方法可以實現一種反向控制結構
  • 部分方法是由子類實現,不同的子類可以提供基本方法的不同實現,更改和增加新的子類很方便,符合開閉原則

缺點

模板方法模式的主要缺點如下:

  • 每個不同的實現都要增加一個子類,這會導致類的個數增加,設計更加抽象,系統更加複雜
  • 由於繼承關係自身的缺點,如果父類添加新的抽象方法時,所有子類都要改一遍

適用場景

模板方法模式的適用場景如下:

  • 將不變的行為提取到父類中實現,將可變的行為留給子類實現
  • 各子類中公共的行為應被提取出來並集中到一個公共父類中以避免代碼重複
  • 需要通過子類來決定父類算法中某個步驟是否執行,實現子類對父類的反向控制

源碼

在 JDK 中,java.util.List 接口的 sort() 方法就是一個模板方法,其使用到部分基本方法,定義了一個排序的默認行為。

如下是源碼部分:

public interface List<E> extends Collection<E> {
    Object[] toArray();

    ListIterator<E> listIterator();

    // 一個默認方法,其中用到了 toArray() 和 listIterator() 這樣的抽象方法
    default void sort(Comparator<? super E> c) {
        Object[] a = this.toArray();
        Arrays.sort(a, (Comparator) c);
        ListIterator<E> i = this.listIterator();
        for (Object e : a) {
            i.next();
            i.set((E) e);
        }
    }
}