前言
設計模式目錄:
- 小菜學習設計模式(一)—模板方法(Template)模式
- 小菜學習設計模式(二)—單例(Singleton)模式
- 小菜學習設計模式(三)—工廠方法(Factory Method)模式
- 小菜學習設計模式(四)—原型(Prototype)模式
- 小菜學習設計模式(五)—控制反轉(Ioc)
- 持續更新中。。。
本篇目錄:
前段時間在亞馬遜買了一本《CLR》的書,當時搞活動買一送一,然后挑了一本《漫談設計模式》,一位不相識的大牛寫的,這幾天閑來無事,翻了幾頁瞧了瞧,感覺還是不錯的,正好小菜也一直想學習設計模式,就決定認真的拜讀下。
小菜寫博文的目的是整理自己所整理的知識,小菜是一個喜歡收集的人,好的東西我都喜歡收藏起來,但是寫出來就是另一回事了,一是鍛煉自己的表達能力及回味所學的知識,而是分享給需要幫助的人。
另外Tony Zhao寫的【原】從頭學習設計模式感覺還是不錯,淺顯易懂,很適合初學者。
對象和模式
雖然一直是用的面向對象的語言,說實話,小菜真的沒有更深層次的了解對象的概念,只能慢慢積累了,其實如果我們不從編程的角度去看待編程,就會發現其實編程只是和普通的解決方案一樣,就像買火車票,去售票廳可以買,在網上可以買,那編程實現的就是網上買票的這個過程,和其他方式實現的效果都是一樣把票買到,只是過程不是一樣。在這本書里面,作者詳細說了下模式(Pattern)的簡史,最開始,模式是在建筑行業提出并運用的,到了后來,由Gof四人幫把模式設計引入到編程世界,并收編了23個最常用的設計模式,得以慢慢發展壯大。
模式定義如下:模式是某一上下文環境中一個問題的解決方案。
但是我更喜歡作者的定義:模式是某一上下文環境中一個問題的“常用”解決方案。
常用并正確的模式才可以算上真正的模式,用鑰匙開門和用錘子撬門都可以進入房子,但是用錘子撬門進入房子并不成為一種模式。
GoF為模式定義了4個基本要素:
- 模式名稱(Pattern name)
- 問題(Problem)
- 解決方案(Solution)
- 效果(Consequence)
模板方法模式-從回家過年說起
馬上就要過年了,大家都很期待,回家的方式有很多種,汽車,火車,船,飛機等,不管什么方式回家,回家過春節就三個過程:買票、回家和家里慶祝。
比如坐火車回家就可以這些寫:

1 public class HapplyPeopleByHuoChe 2 { 3 public void celebrateSpring() 4 { 5 Console.WriteLine("買票...."); 6 Console.WriteLine("坐火車...."); 7 Console.WriteLine("回家慶祝...."); 8 } 9 }
但是有的人需要坐火車,有的人需要坐汽車回家,那我們復制+粘貼修改下:

1 public class HapplyPeopleByQiChe 2 { 3 public void celebrateSpring() 4 { 5 Console.WriteLine("買票...."); 6 Console.WriteLine("坐汽車...."); 7 Console.WriteLine("回家慶祝...."); 8 } 9 }
這樣我們就會發現問題,增加一種交通工具,我們就要復制+粘貼下,這樣代碼就會變得難以維護和開發,針對這種情況,作者提出了一種原則:DRY(Don'T Repeat Yourself,不要復復制你自己),至于這種原則的好與壞我就不闡述了,上面我們那種實現方式的問題其實就是代碼重用,下面說下模板方法模式的運用。
使用繼承
防止代碼重用,OOP的一大特性就是繼承,既然都是買票、回家和在家慶祝,那我們可以把這三種方式抽象出來,代碼如下:

1 public abstract class HapplyPeople2 2 { 3 protected void BuyTicket() 4 { 5 Console.WriteLine("買票...."); 6 } 7 protected abstract void Travel() 8 { 9 //待重寫 10 } 11 protected void Happy() 12 { 13 Console.WriteLine("回家慶祝...."); 14 } 15 }
因為交通方式不同,我們只需要把Travel方法抽象就可以,這樣抽象類的實現類就必須去實現Travel這個抽象方法,而不需要去實現其他的方法。坐火車我們就可以這樣實現:

1 public class HapplyPeopleByHuoChe:HapplyPeople2 2 { 3 protected override void Travel() 4 { 5 Console.WriteLine("坐火車回家...."); 6 } 7 }
相類似的,坐飛機:

1 public class HapplyPeopleByAir : HapplyPeople2 2 { 3 protected override void Travel() 4 { 5 Console.WriteLine("坐飛機回家...."); 6 } 7 }
在上面的例子中HapplyPeople2這個類就是模板,其實在開發一些別的東西的時候我們有時候也會用到Template,比如做一些CMS(內容管理系統)的時候,因為就那幾個頁面,只是頁面的樣式會有所不同,不同的系統還好,如果一個系統用不同的頁面樣式就比較難辦了,這時候就可以用到Template,如下:
里面是一些通過自定義的模板語言創建的模板頁面,生成的時候會轉化為相應的代碼,這樣我們就可以一個系統擁有不同的樣式,只需要在后臺切換下,非常方便。
其實慢慢就會發現模式會運用到任何地方,只要你細心觀察,它就在你身邊。
引入回調
言歸正傳,我們使用模板方法發現有很多好處,比如代碼重用、易于擴展、解決代碼冗余問題等,但是當子類變得越多的時候,就會變得那么不容易維護了。比如我們查詢數據庫的信息:
- 連接Connection對象
- 執行查詢語句
- 處理查詢的結果并分析返回結果
通過上面的需求我們就可以發現1和2都是一樣的,只是返回結果處理的方式不同,回調不同語言有不同的實現方式,C語言使用函數指針實現,java使用內部匿名類實現,C#使用委托(delegate)實現,因為作者整本書都是用java寫的,我電腦沒裝java環境,那就用我們熟悉的C#實現了。
代碼如下:

1 /// <summary> 2 /// 數據庫操作類 3 /// </summary> 4 public class DbHelperOra 5 { 6 public static bool Query(string SQLString, TestTemplete.CallBackDG<DataSet> cb) 7 { 8 using (OracleConnection connection = new OracleConnection("")) 9 { 10 try 11 { 12 //connection.Open(); 13 //OracleDataAdapter command = new OracleDataAdapter(SQLString, connection); 14 DataSet ds = new DataSet(); 15 //command.Fill(ds, "ds"); 16 return cb(ds); 17 } 18 catch (System.Data.OracleClient.OracleException E) 19 { 20 connection.Close(); 21 throw new Exception(E.Message); 22 } 23 } 24 } 25 }

1 /// <summary> 2 /// 測試 3 /// </summary> 4 public class TestTemplete 5 { 6 public delegate bool CallBackDG<T>(T param); 7 public bool Test() 8 { 9 return DbHelperOra.Query("testSql", new CallBackDG<DataSet>(CallBackF)); 10 } 11 public bool CallBackF(DataSet ds) 12 { 13 if (ds.Tables.Count==0 ) 14 { 15 return false; 16 } 17 if (ds.Tables[0].Rows.Count > 0) 18 { 19 return true; 20 } 21 else 22 { 23 return false; 24 } 25 } 26 }
示例代碼下載:TempleteMethod.rar
后記
騷年們,和小菜一起整理學習吧,未完待續。。。
文章列表