2009-10-12 69 views

回答

1

我想給你一些真實世界的例子,並且應當使用模板方法模式的常見情況。

  • 當你想你的程序是「對擴展開放」,也是‘對修改關閉’。這意味着模塊的行爲可以擴展,使得我們能夠在新的模塊的行爲以及根據應用程序需求的變化或滿足新應用程序需求的不同方式,但這種模塊的源代碼是不可侵犯的,任何人都不得對源代碼進行修改,在下面的例子中,您可以在不改變以前的代碼添加工資計算(如遠程類)的新方式。

    公共抽象類薪水{

    public final void calculate() { 
        System.out.println("First shared tasks is done."); 
        getBaseSalary(); 
        System.out.println("Second shared tasks is done."); 
    } 
    
    public abstract void getBaseSalary(); 
    

    }

    公共類每小時薪水擴展{

    @Override 
    public void getBaseSalary() { 
        System.out.println("Special Task is done."); 
    } 
    

    }

    公共類的測試{

    public static void main(String[] args) { 
        Salary salary = .... 
        salary.calculate(); 
    } 
    

    }

  • 當你面對的是通過推遲只是你的算法的一些步驟重複代碼的許多同一直線上。當你正在實現一個方法或函數的內容時,你可以找到你的代碼的一部分,從一個類型到另一個類型。本節的特點是可以在不改變算法(方法或函數)主要結構的情況下重新定義或修改方法或函數的這些部分。例如,如果你想解決這個問題,而這個模式,你會面臨這樣的例子:

function0:功能1:...功能N:

1  1    1 
2  2    2 
...  ...    ... 
5  6    n 
3  3    3 
4  4    4 
...  ...    ... 

正如你所看到的,部分鱈5, 6,n是不同的從一個功能到另一個功能,但是你有共享部分,如1,2,3,4是重複的。讓我們考慮一個着名的java庫的解決方案。

public abstract class InputStream implements Closeable { 

    public abstract int read() throws IOException; 

    public int read(byte b[], int off, int len) throws IOException { 
     .... 

     int c = read(); 
     .... 
    } 

    .... 

} 

public class ByteArrayInputStream extends InputStream { 

    ... 

    public synchronized int read() { 
     return (pos < count) ? (buf[pos++] & 0xff) : -1; 
     } 
    ... 
} 
  • 當你作爲一個框架的設計者,想你的客戶只需爲使用作爲參數傳遞給你的框架,預計回調(執行)的任何可執行代碼在特定時間的論點。這種執行可能會像在同步回調中​​那樣立即執行,或者可能會在以後發生,就像在異步回調中一樣。讓我們考慮一個着名的。

    公共抽象類HttpServlet的擴展GenericServlet類 實現java.io.Serializable { 保護無效的doGet(HttpServletRequest的REQ,HttpServletResponse的RESP){ ... }

    protected void service(HttpServletRequest req, HttpServletResponse resp) 
        throws ServletException, IOException { 
         .... 
         doGet(req, resp); 
         ... 
        } 
        ... 
    } 
    

    }

    公共類MyServlet擴展HttpServlet {

    protected void doGet(HttpServletRequest request, HttpServletResponse response) 
        throws ServletException, IOException { 
    
         //do something 
        ... 
    } 
    ... 
    

    }

7

模板方法圖案提供一種用於執行任何種類的算法或操作的骨架,和它允許子類重新定義部分邏輯。

優點:天生適合構建框架,以便父框架類可以對子節點中實現的方法進行回調。

例子:

  • java.util.AbstractList
  • servlet的doGet和doPost方法
  • MDB的onMessage方法
  • Struts Action類
  • Spring的數據訪問類

缺點:限制你到一個單一的我Java中的繼承。

+0

我只看了一下AbstractList和HttpServlet類。我沒有看到任何「模板方法」。我懷疑你用簡單的「控制反轉」用法混淆了模板方法模式。這個模式不是關於一個基類的方法被框架調用,而是有一個方法來封裝一個算法,該算法可以被覆蓋特殊擴展點的子類自定義(從模板方法調用的基類的可重寫方法,本身並不意味着被覆蓋)。 – 2010-02-14 16:00:16

+0

@Rogerio *你*看不到這個模式並不意味着'HttpServlet'和'AbstractList'不是很好的例子。通過'HttpServelt',子類**可以實現'doGet','doPost'等等,這些是'service'中調用的擴展點(這是容器爲每個請求按容器調用的唯一方法)。使用'AbstractList',子類**可以執行'get','size','set','remove'(只需查看javadoc標題),它們是擴展點。我沒有看到提到的擴展點的任何IoC。 – 2010-02-14 21:07:44

+0

@Rogerio所以,我不是教我什麼Ioc和模板模式,而是先學會認識他們(如果你認爲我以前錯了,要求*你的真相)。也可以學習servlet如何工作。但不要責怪我*你的*無知。因此,我不謝謝你們不相干的倒行逆施,我請你們重新考慮。 – 2010-02-14 21:10:21

1

我已經使用了業務邏輯模板方法,其中一些組件共享相同的進程,但實現稍有不同。

6

模板方法圖案的應用有兩個主要特點:

  1. 有一個基類(在Java中,一個只與protected構造函數和任選聲明爲abstract),這將在客戶端被繼承碼。
  2. 2基團的方法在基類中定義:a)一種或多種模板方法(通常僅一個)和一個或多個原語操作方法(通常超過一個)。每個模板方法代表一個高級操作,在基類自身中根據基本操作實現,這些操作意味着在每個特定的子類中被實現/覆蓋。通常,模板方法是公開的且不可覆蓋的(在Java中爲final);其API文檔必須精確指定它調用的原始操作方法,以及何時(即它必須描述「算法」)。表示算法中的一個步驟的原始操作方法應該是非公開的但可以重寫的(用Java編碼的protected),並且可以有兩種類型:a)在子類中實現的抽象方法必須; b)具有默認/空實現的方法,其中可能在子類中被覆蓋。在Java 6 SDK

一個很好的例子是javax.swing.SwingWorker類(它是一個public final void方法)的方法​​。在這種情況下,原始操作方法是doInBackground()process(List)done()。第一個是抽象的,因此需要在子類中實現;它在後臺線程中由模板方法調用。另外兩個具有空的實現,可以在子類中被重寫;它們分別在EDT(Swing Event Dispatch Thread)中處理期間和處理結束時被調用,以允許更新UI。

在我自己的經驗,我有時用這個模式。 一種這樣的情況下是一個Java基類實現java.util.Iterator接口,其中next()是模板的方法和只有一個負責實例特定域實體類原語操作的方法(這是指迭代的持久性的列表時使用的域實體對象,使用JDBC)。 在同一個應用程序中的一個更好的例子是一個基類,其中模板方法實現了一個多步算法,旨在從給定的持久實體列表中填充「業務實體維護屏幕」(使用Swing);原始操作方法被調用以1)清除當前屏幕狀態,以及2)在屏幕內的表視圖中添加實體;可選地,如果屏幕是可編輯的,則從模板方法調用其他基本操作。

最後,我必須說,雖然這肯定是一個有益的設計模式,不是經常的情況出現在那裏真的是適用的。簡單地擁有一個基類,其中包含在子類中被覆蓋的方法(根據我的經驗,這是一種更爲常見的情況),本身並不足以作爲該模式的應用。

3

模板方法中最重要的事情是,你必須定義一系列的抽象方法的步驟或算法,讓子類替代與這些方法的具體實施。

我在一個文件生成程序中應用。

public abstract DocumentGenerator() 
{ 
    generateHeader(); 
    generateBody(); 
    generateDetails(); 
} 
public HTMLDocGenerator : DocumentGenerator() 
{ 
    public override generateBody() 
    { 
    //generate as in html format 
    } 
} 

你可以有不同的實現,如PDF生成CSV發生器和這裏的價值是他們comform的算法(生成 - >標題,正文,細節)。

2

當存在具有許多實現的算法時,應該使用模板模式。該算法在基類中的函數中定義,實現由基類和子類完成。具有實時例子詳細說明在http://preciselyconcise.com/design_patterns/templatemethod.php

+0

>>「當存在具有許多實現的算法時,應使用模板模式。」不,這是一個錯誤。 你所描述的是*戰略*模式。模板方法模式是關於讓子類替換算法中的某些步驟。 – 2017-11-26 16:53:39

2

給出我會草擬一個現實世界的例子,我使用了一些模板的方法。

在C++計算機視覺算法應用程序中,算法的行爲被設計爲基於在運行時根據枚舉入啓動時加載的配置文件中的枚舉的某些選項假設一些算法行爲的風格。算法的整體框架除了一些關鍵回調之外是完全相同的,否則這些回調會成爲相同的代碼段,爲了調用該級別的不同功能,這些代碼將被殘酷地複製。我想要使​​用的這些回調被抽象到模板方法基類中,並且模板方法模式阻止了所有代碼重複。我們使用的枚舉基本上決定了我實例化我的基類指針所指向的子類,從而藉助該算法將其行爲中的相關位置賦予其相關位。

現在一些背後各種運行算法的口味的動機之一是在線VS軟件的離線功能,控制我們的儀器。離線風格隨其更豐富的調試/診斷輸出而被保留,並且對於某些圖像像素保持局部座標系統,而在線風味將事物保持在絕對座標空間中,並且保持關於具有其所有機器人的運行儀器的特定關注點以及哪些不是。另一個枚舉驅動我們用於某些機器學習的一組分類器之間的選擇,因爲不同的分類器是在不同的數據集之下進行訓練的,否則這些數據集通過代碼體相同地流動,但需要根據一些控制條件該數據已創建。

我相信這種使用情況下,我從什麼被稱爲hole in the middle問題出現了。

1

Template方法定義算法的骨架結構,但 將某些步驟和細節推遲到子類。結構和算法的 流量保持不變,但這些步驟的細節 推遲到子類。

我用模板方法模式編寫文檔內容。有許多不同類型的文檔,每種類型都有自己的小修改。然而,文件編制的主要過程對所有人來說都是一樣的。

相關問題