在
NET發展史中
是具有裡程碑意義的一個版本
從這個版本
NET青出於藍(Java)
而勝於藍
在
NET
帶來的諸多新特性中
我認為泛型是最重要
沒有之一
雖然泛型出現已有多年
連Java都早已借鑒引入了泛型(雖然是語法糖)
可是用泛型的編程思維方式並沒有得到相應的普及
一方面是由於過去大量的Framework仍然是在非泛型時代寫成的
另一方面泛型的設計模式沒有得到發展
改變的時候該到了
來舉一個例子說明這兩點
我們如果寫過網絡數據抓取的代碼
應該熟悉這樣的代碼
var request = WebRequest
Create as HttpWebRequest;
或者這麼寫
也是一樣
var request = HttpWebRequest
Create as HttpWebRequest;
大家可想過
為什麼每次都要as一下?
類似的情況還有
比如做圖像處理的弟兄會熟悉
var bm = Image
FromFile(
e:\\me
jpg
) as Bitmap;
和
var bm = Bitmap
FromFile(
e:\\me
jpg
) 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:\me
jpg
;
var bm = Bitmap
FromFile(path)
;
Console
WriteLine(bm
Path)
Console
WriteLine(bm
GetType()
Name)
輸出結果如下
Path: e:\me
jpg
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<T
K> where T:TreeNode<T
K> 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<RBTreeNode
Int
>
{
/// <summary>
/// 樹節點顏色
是否為紅
/// </summary>
public bool IsRed { get; set; }
public override string ToString()
{
return this
Value +
+ (this
IsRed ?
R
:
B
)
}
}
這個是AVL樹
class AvlTreeNode : TreeNode<AvlTreeNode
Int
>
{
/// <summary>
/// 節點的平衡度
/// </summary>
public int Balance { get; set; }
public override string ToString()
{
return
Balance:
+ Balance +
Value:
+ this
Value;
}
}
不但完全符合OCP原則
而且再也不需要as來強制轉換節點類型了
這肯定不是我的首創
其實
NET Framework中已經不少這樣的設計
比如IComparable<T>接口
也有不少優秀的框架采用了類似的設計
比如大石頭同學的ORM框架NewLife
XCode
看上去也很簡單吧
但是很多人思維還停留在面向對象語言剛誕生的階段
還不習慣用這種設計模式
我認為這種寫法足夠典型和通用
足以得上一種設計模式
而且是
NET特殊優勢
獨特魅力
說到設計模式
其實GOF提出的
種設計模式多年了
已經過時
出現了許多新模式(比如並發編程方面
參考Wiki Design Pattern)
舊有的模式中
有的已經包含在
NET語言特性中
有的模式實現方式已經改頭換面
尤其在泛型出現後
許多模式的實現可以變得簡潔許多
優雅許多
不要一遍遍炒過去的冷飯
設計模式應該與時俱進
永遠是充滿新鮮活力的話題
From:http://tw.wingwit.com/Article/program/net/201311/13754.html