設計模式 9 —— 模板方法模式 設計模式 1 ——觀察者模式 設計模式 2 —— 裝飾者模式 設計模式 3 —— 迭代器和組合模式(迭代器) 設計模式 4 —— 迭代器和組合模式(組合) 設計模式

設計模式目錄:html

設計模式 1 ——觀察者模式java

設計模式 2 —— 裝飾者模式 算法

設計模式 3 —— 迭代器和組合模式(迭代器)設計模式

設計模式 4 —— 迭代器和組合模式(組合)數組

設計模式 5 —— 工廠模式ide

設計模式 6 —— 單件模式post

設計模式 7 —— 命令模式測試

設計模式 8 —— 適配器和外觀模式ui

設計模式 9 —— 模板方法模式this

設計模式 10 —— 狀態模式

概述

介紹

模板方法抽象類

模板方法的UML圖

模板方法模式定義

JDK中模板方法模式的使用

Java API中的模板方法

參考

 

模板模式是一種行爲設計模式,它的實現思路是,建立一個樁方法,而且定義一些步驟讓子類來實現。模板方法定義了一個算法的執行步驟,或者說可以提供一種默認的實現,這種實現歸納一部分子類或者所有子類的共同部分。

舉一個例子幫助理解,假設提供一種造房子的算法。算法的步驟就是模擬造房子的過程:建地基、建支撐,最後添加牆和窗戶 – 1. Fundation,2. Pillars,3. Walls,4. Windows。最重要的一點就是不能改變此建造過程,好比不可能在沒用地基的時候就開始建造窗戶。這個例子中,咱們就建立了一個模板方法 – 將使用不一樣的方法完成對房子的建造。

爲了確保子類不能重寫(override)這個模板方法,應當使用final

模板方法抽象類

由於設計爲一些方法的具體實現留待子類中,因此不得不安排基類爲一個抽象類

HouseTemple.java

 1 package cn.telling.test.action;
 2 
 3 /**
 4  * 
 5  * @ClassName: HouseTemplate TODO
 6  * @author xingle
 7  * @date 2015-9-24 下午2:04:22
 8  */
 9 public abstract class HouseTemplate {
10     // template method, final so subclasses can't override
11     public final void buildHouse() {
12         buildFoundation();
13         buildPillars();
14         buildWalls();
15         buildWindows();
16         System.out.println("House is built.");
17     }
18 
19     // default implementation
20     private void buildWindows() {
21         System.out.println("Building Glass Windows");
22     }
23 
24     // methods to be implemented by subclasses
25     public abstract void buildWalls();
26 
27     public abstract void buildPillars();
28 
29     private void buildFoundation() {
30         System.out.println("Building foundation with cement,iron rods and sand");
31     }
32 
33 }

 

buildHouse()是模板方法並定義了在建造房子過程當中一系列方法的執行順序。

WoodenHouse.java

 1 package cn.telling.test.action;
 2 
 3 /**
 4  * 
 5  * @ClassName: WoodenHouse
 6  * TODO
 7  * @author xingle
 8  * @date 2015-9-24 下午2:07:06
 9  */
10 public class WoodenHouse extends HouseTemplate{
11 
12     /**
13      * 
14      * @Description: TODO
15      * @author xingle
16      * @data 2015-9-24 下午2:07:15
17      */
18     @Override
19     public void buildWalls() {
20         System.out.println("Building Wooden Walls");
21         
22     }
23 
24     /**
25      * 
26      * @Description: TODO
27      * @author xingle
28      * @data 2015-9-24 下午2:07:15
29      */
30     @Override
31     public void buildPillars() {
32         System.out.println("Building Pillars with Wood coating");
33     }
34 
35 }

 

此處也應當對其餘方法進行重寫,可是爲了簡便,此處沒用完成。

GlassHouse.java

 1 package cn.telling.test.action;
 2 
 3 /**
 4  * 
 5  * @ClassName: GlassHouse
 6  * TODO
 7  * @author xingle
 8  * @date 2015-9-24 下午2:05:28
 9  */
10 public class GlassHouse extends HouseTemplate{
11 
12     /**
13      * 
14      * @Description: TODO
15      * @author xingle
16      * @data 2015-9-24 下午2:05:39
17      */
18     @Override
19     public void buildWalls() {
20         System.out.println("Building Glass Walls");
21     }
22 
23     /**
24      * 
25      * @Description: TODO
26      * @author xingle
27      * @data 2015-9-24 下午2:05:39
28      */
29     @Override
30     public void buildPillars() {
31         System.out.println("Building Pillars with glass coating");
32         
33     }
34 
35 }

 

使用模板方法

用一個測試程序來測試此處已完成的模板方法。

HouseClient.java

 1 package cn.telling.test.action;
 2 
 3 /**
 4  * 
 5  * @ClassName: HousingClient TODO
 6  * @author xingle
 7  * @date 2015-9-24 下午2:06:33
 8  */
 9 public class HousingClient {
10     public static void main(String[] args) {
11 
12         HouseTemplate houseType = new WoodenHouse();
13 
14         // using template method
15         houseType.buildHouse();
16         System.out.println("************");
17 
18         houseType = new GlassHouse();
19 
20         houseType.buildHouse();
21     }
22 
23 }

 

注意,client正在調用基類的模板方法而且依賴於不一樣步驟的實現細節,即這些正在使用的方法,他們一些來着基類另外一些來自子類。上述程序的輸出:

 

模板方法的UML圖

模板方法模式定義

模板方法模式定義一個操做中算法的骨架,而將這些步驟延遲到子類中,模板方法使得子類能夠不改變一個算法的結構便可從新定義該算法的某些特定步驟。

這個模式是用來建立一個算法的模板。什麼是模板?如你所見的,模板就是一個方法。更具體地說,這個方法將算法定義成一組步驟,其中的任何步驟均可以是抽象的,由子類負責實現,這能夠確保算法的結構保持不變,同時由子類提供部分實現。

JDK中模板方法模式的使用

  • java.io.InputStream, java.io.OutputStream, java.io.Reader 以及 java.io.Writer 中全部非抽象方法。
  • java.util.AbstractList, java.util.AbstractSet 以及 java.util.AbstractMap中全部非抽象方法。

重要提示

  • 模板方法應該是由肯定的步驟組成。這些步驟的順序是固定的。基類與子類之間某些方法或者實現能夠有所不一樣。模板方法應該是final的。
  • 大多時候,子類的調用的方法是來自於超類。可是在模板模式中,超類的模板方法調用的方法卻來至於子類,這就是著名的Hollywood原則-「don’t call us, we’ll call you」。
  • 基類方法的默認實現被退化爲鉤子Hooks的概念,他們被設計在子類中被重寫,若是你指望一些方法在子類中不被重寫,你可讓他們爲final。好比在例子中buildFoundation()方法是final的,由於不但願它在子類中被重寫。

Java API中的模板方法

用模板方法排序

java數組類的設計者提供給咱們一個方便的模板方法用來排序。

public static void sort(Object[] a) {
        if (LegacyMergeSort.userRequested)
            legacyMergeSort(a);
        else
            ComparableTimSort.sort(a);
    }

    /** To be removed in a future release. */
    private static void legacyMergeSort(Object[] a) {
        Object[] aux = a.clone();
        mergeSort(aux, a, 0, a.length, 0);
    }

 

其中 mergeSort() 方法包含排序算法,此算法依賴於compareTo() 方法的實現來完成算法。咱們須要實現compareTo()方法,「填補」模板方法的缺憾。

/**
     * Src is the source array that starts at index 0
     * Dest is the (possibly larger) array destination with a possible offset
     * low is the index in dest to start sorting
     * high is the end index in dest to end sorting
     * off is the offset to generate corresponding low, high in src
     * To be removed in a future release.
     */
    private static void mergeSort(Object[] src,
                                  Object[] dest,
                                  int low,
                                  int high,
                                  int off) {
        int length = high - low;

        // Insertion sort on smallest arrays
        if (length < INSERTIONSORT_THRESHOLD) {
            for (int i=low; i<high; i++)
                for (int j=i; j>low &&
                         ((Comparable) dest[j-1]).compareTo(dest[j])>0; j--)
                    swap(dest, j, j-1);
            return;
        }

 

數組的排序模板方法已經提升了算法,可是你必須讓這個模板方法知道如何比較鴨子。你所要作的事情就是,實現一個compareTo() 方法。

可是數組沒法繼承,該如何使用sort()?

sort() 的設計者但願這個方法能使用於全部的數組,因此他們把sort() 變成事靜態的方法,這樣一來,任何數組均可以使用這個方法。它使用起來和它被定義在超類中是同樣的。實際上,sort()並非真正定義在超類中,因此sort() 方法須要知道你已經實現了compareTo()方法,不然就沒法進行排序。

要達到這一點,設計者利用了Comparable接口。你必須實現這個接口,提供這個接口所聲明的方法,也就是compareTo()。

 

鴨子的實現:

 1 package cn.telling.test.action;
 2 
 3 /**
 4  * 
 5  * @ClassName: Duck
 6  * TODO
 7  * @author xingle
 8  * @date 2015-9-24 下午3:32:47
 9  */
10 public class Duck implements Comparable<Object>{
11     //咱們須要讓鴨子類實現Comparable 接口,由於咱們沒法真的讓鴨子數組去繼承數組
12     private String name ;
13     private int weight;
14     
15     public Duck(String name,int weight){
16         this.name = name;
17         this.weight = weight;
18     }
19     
20     public String toString(){
21         return name+" weight"+weight;
22     }
23 
24     /**
25      * 排序所要的方法
26      * @Description: TODO
27      * @param o
28      * @return
29      * @author xingle
30      * @data 2015-9-24 下午3:42:43
31      */
32     @Override
33     public int compareTo(Object o) {
34         //compareTo() 須要傳入一隻鴨子,和自己這種鴨子作比較
35         Duck otherDuck = (Duck) o;
36         if(this.weight<otherDuck.weight){
37             return -1;
38         } else if(this.weight == otherDuck.weight){
39             return 0;            
40         } else {
41             return 1;
42         }
43     }
44 }

 

測試排序鴨子的程序:

 1 package cn.telling.test.action;
 2 
 3 import java.util.Arrays;
 4 
 5 /**
 6  * 
 7  * @ClassName: DuckSortTestDrive
 8  * TODO
 9  * @author xingle
10  * @date 2015-9-24 下午3:35:44
11  */
12 public class DuckSortTestDrive {
13     
14     public static void main(String[] args) {
15         Duck[] ducks = { new Duck("D1", 8), new Duck("D2", 6),
16                 new Duck("D3", 2),new Duck("D4", 5) };
17         System.out.println("Bofore sorting  ");
18         dispaly(ducks);
19         //調用Array類的靜態方法sort(),讓後將鴨子數組當作參數傳入
20         Arrays.sort(ducks);
21         System.out.println("After sorting  ");
22         dispaly(ducks);
23     }
24 
25     /**
26      * TODO
27      * @param ducks
28      * @author xingle
29      * @data 2015-9-24 下午3:39:17
30      */
31     public static void dispaly(Duck[] ducks) {
32         for(int i = 0;i<ducks.length;i++){
33             System.out.println(ducks[i]);
34         }
35         
36     }
37 
38 }

 

執行結果:

 


參考:

  1. Java中的模板模式
  2. [Head First設計模式]雲南米線館中的設計模式——模版方法模式
  3. 《First Head 設計模式》 第8章 封裝算法:模板方法模式
相關文章
相關標籤/搜索