代碼僅僅是說明問題,和實際的有所不同 在項目開發過程中,有這樣的需求:定義一個查詢窗體使用DataGrid顯示列表 雙擊Grid后打開指定記錄的編輯頁面,窗體類為FormSearchEntity于是這么寫了 private void Grid_DoubleClick(object sender,System.EventArgs e) { string entityID = 雙擊記錄的ID字段值; //這個有固定的辦法 FormEntity frmEntity = new FormEntity(entityID); ........ frmEntity.Show(); } 其中的FormEntity就是對業務實體的編輯界面,在構造函數中傳入一個ID,然后 加載該記錄的相關數據,在這里不作重點解釋。
接下來有要在查詢界面上添加一個按鈕“Go”,執行的動作和Grid雙擊是一樣的,就是 在Grid中選中記錄,點擊Go打開實體的操作界面。
這樣,就使用重構中的Extract Method手法: private void Grid_DoubleClick(object sender,System.EventArgs e) { string entityID = 雙擊記錄的ID字段值; OpenEntityForm(entityID); } private void btnGo_Click(object sender,System.EventArgs e ) { string entityID = 雙擊記錄的ID字段值; OpenEntityForm(entityID); } private void OpenEntityForm(string entityID) { FormEntity frmEntity = new FormEntity(entityID); ........ frmEntity.Show(); }
到現在看來,這樣作有什么用呢?直接在Go的Click時間中調用Grid的DoubleClick不就行了嗎?事實上Extract Method不僅僅是防止重復代碼 同時也可以提高代碼的可重用性,作用在下面會看到。
現在,又要對另一個的表進行同樣的操作,那就再定義一個窗體,把上面的代碼改改就成了,但是就出現了重復代碼,這是不好的味道。那么這樣作:把OpenEntityForm方法改為Virtual,同時聲明為Protected,里面的代碼都去掉 protected void OpenEntityForm(string entityID) { } 把窗體更名為FormSearchEntityBase再重新寫一個類FormSearchEntityA來繼承FormSearchEntityBase,override父類的OpenEntityForm方法
protected override void OpenEntityForm(string entityID) { FormEntityA frmEntityA = new FormEntityA(entityID); ........ frmEntityA.Show(); }
實體B的查詢界面也一樣FormSearchEntityB繼承自FormSearchEntityBase,override父類的OpenEntityForm方法 protected override void OpenEntityForm(string entityID) { FormEntityB frmEntityB = new FormEntityB(entityID); ........ frmEntityB.Show(); } 這樣,如果后面還有相同的需求,就從FormSearchEntityBase繼承一個類,override父類的OpenEntityForm方法就可以了
現在,來看看TemplateMethod模式 意圖: 定義一個操作中的算法的骨架,而將一些步驟延遲到子類中。 適用性: 一次性實現一個算法的不變的部分,并將可變的行為留給子類來實現。 各子類中公共的行為應被提取出來并集中到一個公共父類中以避免代碼重復 控制子類擴展
例子代碼: namespace TemplateMethod_DesignPattern { using System;
class Algorithm { public void DoAlgorithm() { Console.WriteLine("In DoAlgorithm"); // do some part of the algorithm here // step1 goes here Console.WriteLine("In Algorithm - DoAlgoStep1"); // . . .
// step 2 goes here Console.WriteLine("In Algorithm - DoAlgoStep2"); // . . .
// Now call configurable/replacable part DoAlgoStep3();
// step 4 goes here Console.WriteLine("In Algorithm - DoAlgoStep4"); // . . .
// Now call next configurable part DoAlgoStep5(); }
virtual public void DoAlgoStep3() { Console.WriteLine("In Algorithm - DoAlgoStep3"); }
virtual public void DoAlgoStep5() { Console.WriteLine("In Algorithm - DoAlgoStep5"); } }
class CustomAlgorithm : Algorithm { public override void DoAlgoStep3() { Console.WriteLine("In CustomAlgorithm - DoAlgoStep3"); }
public override void DoAlgoStep5() { Console.WriteLine("In CustomAlgorithm - DoAlgoStep5"); } }
/// <summary> /// Summary description for Client. /// </summary> public class Client { public static int Main(string[] args) { CustomAlgorithm c = new CustomAlgorithm();
c.DoAlgorithm();
return 0; } } }
再來對比下上面對窗體類進行改動的代碼和TemplateMethod的例子代碼,這就是一個TemplateMethod模式了
有一種觀點說在設計期使用設計模式常會導致過渡設計,目前的敏捷方法和重構都漸漸提倡代碼演化和重構達到設計模式。 我也是在寫完代碼后才發現這已經是一個模式了。
|