熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> .NET編程 >> 正文

.NET獨有的精巧泛型設計模式

2013-11-13 10:28:14  來源: .NET編程 
    在NET發展史中是具有裡程碑意義的一個版本從這個版本NET青出於藍(Java)而勝於藍NET 帶來的諸多新特性中我認為泛型是最重要沒有之一
   
    雖然泛型出現已有多年連Java都早已借鑒引入了泛型(雖然是語法糖)可是用泛型的編程思維方式並沒有得到相應的普及一方面是由於過去大量的Framework仍然是在非泛型時代寫成的另一方面泛型的設計模式沒有得到發展改變的時候該到了
   
    來舉一個例子說明這兩點我們如果寫過網絡數據抓取的代碼應該熟悉這樣的代碼
   
    var request = WebRequestCreate as HttpWebRequest;
   
    或者這麼寫也是一樣
   
    var request = HttpWebRequestCreate as HttpWebRequest;
   
    大家可想過為什麼每次都要as一下?
   
    類似的情況還有比如做圖像處理的弟兄會熟悉
   
    var bm = ImageFromFile(e:\\mejpg) as Bitmap;
   
    和
   
    var bm = BitmapFromFile(e:\\mejpg) as Bitmap;
   
    我想過但沒想明白上面兩種寫法都是調用父類的工廠方法實際返回了一個子類的實例顯然即使不了解OCP憑直覺也應該想到父類的實現中不應該被子類所決定寫WebRequest和Image的前輩可能也覺得直接返回子類實例不妥所以陰險地把方法簽名的返回類型改成了父類
   
    雖然這種行徑值得嚴重鄙視NET程序員大都是人雲亦雲照葫蘆畫瓢的好學生所以這個問題多年了也沒有修改
   
    理想的設計應該是這樣父類的每個子類都有獨立的工廠方法返回其自身的實例這樣做法在泛型出現前非常笨拙得不償失但有了泛型就可以精巧地實現


    
    以模擬Image類為例Image和BitMap實現如下
   
    class Image<T> where T:Image<T> new()
   
    {
   
    public string Path { get; set; }
   
    public static T FromFile(string path)
   
    {
   
    return new T() { Path = path };
   
    }
   
    }
   
    class Bitmap:Image<Bitmap>
   
    {
   
    }
   
    Image自身的工廠方法就沒有存在的必要了
   
    可以簡單地測試一下
   
    var path = @e:\mejpg;
   
    var bm = BitmapFromFile(path) ;
   
    ConsoleWriteLine(bmPath)
   
    ConsoleWriteLine(bmGetType()Name)
   
    輸出結果如下
   
    Path: e:\mejpg
   
    Type: Bitmap
   
    為了讓大家更熟悉一下再舉一個實現數據結構中的二叉樹作例子
   
    傳統的樹節點類無論無論C/C++/Java都是類似這樣
   
    class TreeNode
   
    {
   
    public TreeNode LeftChild { get; set; }
   
    public TreeNode RightChild { get; set; }
   
    public TreeNode Parent { get; set; }
   
    public int Value { get; set; }
   
    }
   
    大家知道二叉樹又分好幾種AVL樹B樹紅黑樹等等實現特殊的二叉樹數據結構勢必要繼承TreeNode由於樹節點的類型中有類型為基類的成員所以在子類操作這些成員時往往也要強制轉換類型這比Image和WebRequest的例子只在實例創建時轉換類型還麻煩
   
    這就該泛型模式一顯身手的好機會了請看其父類型的實現
   
    /// <typeparam name=T>Type of the node</typeparam>
   
    /// <typeparam name=K>Type of the node value</typeparam>
   
    class TreeNode<TK> where T:TreeNode<TK> where K: IComparable<K>
   
    {
   
    public T LeftChild { get; set; }
   
    public T RightChild { get; set; }
   
    public T Parent { get; set; }
   
    public K Value { get; set; }
   
    }
   
    之後實現任何一種特殊二叉樹結構比如RBTreeNode代表紅黑樹節點可以這樣
   
    class RBTreeNode : TreeNode<RBTreeNodeInt>
   
    {
   
    /// <summary>
   
    /// 樹節點顏色是否為紅
   
    /// </summary>
   
    public bool IsRed { get; set; }
   
    public override string ToString()
   
    {
   
    return thisValue + + (thisIsRed ? R : B
   
    }
   
    }
   
    這個是AVL樹
   
    class AvlTreeNode : TreeNode<AvlTreeNodeInt>
   
    {
   
    /// <summary>
   
    /// 節點的平衡度
   
    /// </summary>
   
    public int Balance { get; set; }
   
    public override string ToString()
   
    {
   
    return Balance: + Balance + Value: + thisValue;
   
    }
   
    }
   
    不但完全符合OCP原則而且再也不需要as來強制轉換節點類型了


    
    這肯定不是我的首創其實NET Framework中已經不少這樣的設計比如IComparable<T>接口也有不少優秀的框架采用了類似的設計比如大石頭同學的ORM框架NewLifeXCode
   
    看上去也很簡單吧但是很多人思維還停留在面向對象語言剛誕生的階段還不習慣用這種設計模式我認為這種寫法足夠典型和通用足以得上一種設計模式而且是NET特殊優勢獨特魅力
   
    說到設計模式其實GOF提出的種設計模式多年了已經過時出現了許多新模式(比如並發編程方面參考Wiki Design Pattern)舊有的模式中有的已經包含在NET語言特性中有的模式實現方式已經改頭換面尤其在泛型出現後許多模式的實現可以變得簡潔許多優雅許多
   
    不要一遍遍炒過去的冷飯設計模式應該與時俱進永遠是充滿新鮮活力的話題


From:http://tw.wingwit.com/Article/program/net/201311/13754.html
    推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.