程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> .NET實例教程 >> 模板方法(Template Method)

模板方法(Template Method)

編輯:.NET實例教程

無處不在的Template Method
    如果你只想掌握一種設計模式,那麼它就是Template Method!
動機(Motivate):
    變化 -----是軟件設計的永恆主題,如何管理變化帶來的復雜性?設計模式的藝術性和復雜度就在於如何
分析,並發現系統中的變化和穩定點,並使用特定的設計方法來應對這種變化。
意圖(Intent):
    定義一個操作中的算法的骨架,而將一些步驟延遲到子類中。Template Method使得子類可以不改變一個算法的結構即可重定義該算法的某些特定步驟。                                                        -------《設計模式》GOF
結構圖(Struct):
                   
適用性:
   

1.一次性實現一個算法的不變的部分,並將可變的行為留給子類來實現。

2.各子類中公共的行為應被提取出來並集中到一個公共父類中以避免代碼重復。這是Opdyke和Johnson所描述過的“重分解以一般化”的一個很好的例子。首先識別現有代碼中的不同之處,並且將不同之處分離為新的操作。最後,用一個調用這些新的操作的模板方法來替換這些不同的代碼。

3.控制子類擴展。

模板方法只在特定點調用“Hook”操作,這樣就只允許在這些點進行擴展。
生活中的例子:
               
代碼實現:

    假如我們需要簡單的讀取Northwind數據庫中的表的記錄並顯示出來。對於數據庫操作,我們知道不管讀取的是哪張表,它一般都應該經過如下這樣的幾步:

1.連接數據庫(Connect)

2.執行查詢命令(Select)

3.顯示數據(Display)

4.斷開數據庫連接(Disconnect)

這些步驟是固定的,但是對於每一張具體的數據表所執行的查詢卻是不一樣的。顯然這需要一個抽象角色,給出頂級行為的實現。如下圖:                                 

;                                                               
                        
Template Method模式的實現方法是從上到下,我們首先給出頂級框架DataAccessObject的實現邏輯:

 1 public abstract class DataAccessObject
 2 
 3 {
 4    

255)">protected string connectionString;
 5 
 6     protected DataSet dataSet;
 7 
 8     protected virtual void Connect()
 9 
10     { 
11         connectionString = 
12 
13             "Server=.;User Id=sa;PassWord=;Database=Northwind";
14 
15     }
16 

128)">17    protected  abstract void Select();
18 
19     protected abstract void Display();
20 
21 
22     protected virtual void Disconnect()
23 
24     {
25         connectionString = "";
26     }
27 
28     

0)">// The "Template Method" 
29 
30     public void Run()
31 
32     {
33         Connect();
34 
35         Select();
36 
37         Display();
38 
39         Disconnect();
40     }
41 }顯然在這個頂級的框架DataAccessObject中給出了固定的輪廓,方法Run()便是模版方法,Template Method模式也由此而得名。而對於Select()和Display()這兩個抽象方法則留給具體的子類去實現,如下圖:
              



 1 class CategorIEs : DataAccessObject
 2 
 3 {
 4     protected override void Select()
 5     {
 6         string sql = "select CategoryName from CategorIEs";
 7 
 8         SqlDataAdapter dataAdapter = new SqlDataAdapter(
 9 
10 

0)">            sql, connectionString);
11 
12         dataSet = new DataSet();
13 
14         dataAdapter.Fill(dataSet, "CategorIEs");
15 
16     }
17 
18     protected override void Display()
19 
20     {
21 
22         Console.WriteLine("0)">CategorIEs ---- ");
23 
24         DataTable dataTable = dataSet.Tables["CategorIEs"];
25 
26         foreach (DataRow row in dataTable.Rows)
27 
28         {
29 
30             Console.WriteLine(row["CategoryName"].ToString());
31 
32         }
33 
34 

0)">        Console.WriteLine();
35 
36     }
37 }

 1 class Products : DataAccessObject
 2 
 3 {
 4     protected override void Select()
 5 
 6     {
 7         string sql = "select top 10 ProductName from Products";
 8 
 9 

0)">        SqlDataAdapter dataAdapter = new SqlDataAdapter(
10 
11             sql, connectionString);
12 
13         dataSet = new DataSet();
14 
15         dataAdapter.Fill(dataSet, "Products");
16 
17     }
18 
19     protected override void Display()
20 

128)">21     {
22 
23         Console.WriteLine("Products ---- ");
24 
25         DataTable dataTable = dataSet.Tables["Products"];
26 
27         foreach (DataRow row in dataTable.Rows)
28 
29         {
30             Console.WriteLine(row["ProductName"].ToString());
31 

128)">32         }
33 
34         Console.WriteLine();
35 
36     }
37 
38 }
再來看看客戶端程序的調用,不需要再去調用每一個步驟的方法:
1 public class App
 2 
 3 {
 4     static void Main()
 5     {
 6 
 7         DataAccessObject dao;
 8 

128,128)"> 9 
10         dao = new CategorIEs();
11 
12         dao.Run();
13 
14 
15         dao = new Products();
16 
17         dao.Run();
18 
19         // Wait for user 
20 
21         Console.Read();
22 
23     }


24 
25 }

在上面的例子中,需要注意的是:

1.對於Connect()和Disconnect()方法實現為了virtual,而Select()和Display()方法則為abstract,這是因為如果這個方法有默認的實現,則實現為virtual,否則為abstract。

2.Run()方法作為一個模版方法,它的一個重要特征是:在基類裡定義,而且不能夠被派生類更改。有時候它是私有方法(private method),但實際上它經常被聲明為protected。它通過調用其它的基類方法(覆寫過的)來工作,但它經常是作為初始化過程的一部分被調用的,這樣就沒必要讓客戶端程序員能夠直接調用它了。

3.在一開始我們提到了不管讀的是哪張數據表,它們都有共同的操作步驟,即共同點。因此可以說Template Method模式的一個特征就是剝離共同點。
Template Mehtod實現要點:

1.Template Method模式是一種非常基礎性的設計模式,在面向對象系統中有著大量的應用。它用最簡潔的機制(虛函數的多態性)為很多應用程序框架提供了靈活的擴展點,是代碼復用方面的基本實現結構。

2.除了可以靈活應對子步驟的變化外,“不用調用我,讓我來調用你(Don''t call me ,let me call you)”的反向控制結構是Template Method的典型應用。“Don’t call me.Let me call you”是指一個父類調用一個子類的操作,而不是相反。

3.在具體實現方面,被Template Method調用的虛方法可以具有實現,也可以沒有任何實現(抽象方法,純虛方法),但一般推薦將它們設置為protected方法。
 

  1. 上一頁:
  2. 下一頁: