1. 程式人生 > >模板方法模式(Template Method)

模板方法模式(Template Method)

Template Method模式定義一個操作中的演算法的骨架,而將一些步驟延遲到子類中。Template Method使得子類可以不改變一個演算法的結構即可重定義該演算法的某些特定步驟。
• 一次性實現一個演算法的不變的部分,並將可變的行為留給子類來實現。
• 各子類中公共的行為應被提取出來並集中到一個公共父類中以避免程式碼重複。

按照Template Method模式提煉方法來重構程式碼,是實現很多其它模式的基礎。

案例 1: 以下通過一個氣泡排序(Bubble)程式一步一步重構提煉方法實現Template Method模式。
Step 1: 先寫一個int陣列的氣泡排序程式,驗證演算法

public class BubbleSorter{
    public int[] sort(int[] args) {
        if(args == null) return null;
        if(args.length <= 1) return args;
        for(int i = args.length-2; i > 0; i--) {
            for(int j = 0; j <= i; j++) {
                if(args[j] > args[j+1]) {
                    int
temp = args[j]; args[j] = args[j+1]; args[j+1] = temp; } } } return args; } }

Step 2: 考慮到需要支援double陣列的排序需求,對BubbleSorter類實施重構,先從提煉方法開始重構。

public class BubbleSorter{
    public int[] sort(int[] args) {
        if
(args == null) return null; if(args.length <= 1) return args; for(int i = args.length-2; i > 0; i--) { for(int j = 0; j <= i; j++) { if(outOfOrder(args, j)) { swap(args, j); } } } return args; } private boolean outOfOrder(int[] args, int index) { return args[index] > args[index + 1]; } private void swap(int[] args, int index) { int temp = args[index]; args[index] = args[index+1]; args[index+1] = temp; } }

Step 3: 提煉出來的輔助方法swap 和outOfOrder的帶一個數組引數,這樣它們依賴於陣列型別,考慮除去這個陣列引數,需要新增一個成員變數來持有被排序的陣列。

public class BubbleSorter {
    private int[] args;
    private int length = 0;
    public int[] sort(int[] args) {
        if(args == null) return null;
        this.args = args;
        length = args.length;
        if(length <= 1) return args;
        for(int i = length -2; i > 0; i--) {
            for(int j = 0; j <= i; j++) {
                if(outOfOrder(j)) {
                    swap(j);
                }
            }
        }
        return args;
    }
    private boolean outOfOrder(int index) {//Extract Method
        return args[index] > args[index + 1];
    }

    private void swap(int index) {//Extract Method
        int temp = args[index];
        args[index] = args[index+1];
        args[index+1] = temp;
    }
}

Step 3: 可以看到sort方法中的for 迴圈語句不依賴於陣列,再提煉方法。

public class BubbleSorter {
    private int[] args;
    private int length = 0;
    public int[] sort(int[] args) {
        if(args == null) return null;
        this.args = args;
        length = args.length;
        if(length <= 1) return args;
        doSort();
        return args;
    }
    private void doSort() {//Extract Method
        for(int i = length -2; i > 0; i--) {
            for(int j = 0; j <= i; j++) {
                if(outOfOrder(j)) {
                    swap(j);
                }
            }
        }
    }
    private boolean outOfOrder(int index) {
        return args[index] > args[index + 1];
    }

    private void swap(int index) {
        int temp = args[index];
        args[index] = args[index+1];
        args[index+1] = temp;
    }
}

Step 4: 如論是Int陣列還是double陣列, 都會用到doSort, swap and outOfOrder方法,使用Template Method 模式,提煉抽象超類。

public abstract class AbstractBubbleSorter {
    protected int length = 0; //protected 
    public void doSort() {//template method
        for(int i = length -2; i > 0; i--) {
            for(int j = 0; j <= i; j++) {
                if(outOfOrder(j)) {
                    swap(j);
                }
            }
        }
    }
    public abstract boolean outOfOrder(int index);
    public abstract void swap(int index);
}

Step 5: 將BubbleSorter更名成IntBubbleSorter並繼承AbstractBubbleSorter類:

public class IntBubbleSorter extends AbstractBubbleSorter {
    private int[] args;
    public int[] sort(int[] args) {
        if(args == null) return null;
        this.args = args;
        length = args.length;
        if(length <= 1) return args;
        doSort();
        return args;
    }
    public boolean outOfOrder(int index) {
        return args[index] > args[index + 1];
    }

    public void swap(int index) {
        int temp = args[index];
        args[index] = args[index+1];
        args[index+1] = temp;
    }
}

同上寫出 DoubleBubberSorter 類

Factory Method通常通過Template Method呼叫。