浅谈.NET独有精巧泛型设计模式

虽然泛型出现已有多年,连Java都早已借鉴引入了泛型(虽然是语法糖),可是用泛型的编程思维方式并没有得到相应的普及。一方面是由于过去大量的Framework仍然是在非泛型时代写成的,另一方面泛型的设计模式没有得到发展,改变的时候该到了。

创新互联公司专注于焦作网站建设服务及定制,我们拥有丰富的企业做网站经验。 热诚为您提供焦作营销型网站建设,焦作网站制作、焦作网页设计、焦作网站官网定制、微信平台小程序开发服务,打造焦作网络公司原创品牌,更为您提供焦作网站排名全网营销落地服务。

来举一个例子说明这两点。我们如果写过网络数据抓取的代码,应该熟悉这样的代码:

 
 
 
  1. var request = WebRequest.Create("http://www.cnblogs.com/") as HttpWebRequest; 

或者这么写,也是一样:

 
 
 
  1. var request = HttpWebRequest.Create("http://www.cnblogs.com/") as HttpWebRequest; 

大家可想过,为什么每次都要as一下?

类似的情况还有,比如做图像处理的弟兄会熟悉:

 
 
 
  1. var bm = Image.FromFile("e:\\me.jpg") as Bitmap; 

 
 
 
  1. var bm = Bitmap.FromFile("e:\\me.jpg") as Bitmap; 

我想过,但没想明白。上面两种写法,都是调用父类的工厂方法,实际返回了一个子类的实例。显然,即使不了解OCP,凭直觉也应该想到,父类的实现中不应该被子类所决定。写WebRequest和Image的前辈可能也觉得直接返回子类实例不妥,所以阴险地把方法签名的返回类型改成了父类。

虽然这种行径值得严重鄙视。但.NET程序员大都是人云亦云,照葫芦画瓢的好学生,所以这个问题多年了也没有修改。

理想的设计应该是这样:父类的每个子类,都有独立的工厂方法,返回其自身的实例。这样做法,在泛型出现前非常笨拙,得不偿失,但有了泛型,就可以精巧地实现。

以模拟Image类为例,Image和BitMap实现如下:

 
 
 
  1. class Image where T:Image, new()  
  2. {  
  3.     public string Path { get; set; }  
  4.  
  5.     public static T FromFile(string path)  
  6.     {  
  7.         return new T() { Path = path };  
  8.     }  
  9. }  
  10.  
  11. class Bitmap:Image  
  12. {  

Image自身的工厂方法,就没有存在的必要了。

可以简单地测试一下:

 
 
 
  1. var path = @"e:\me.jpg";  
  2. var bm = Bitmap.FromFile(path); ;  
  3.  
  4. Console.WriteLine(bm.Path);  
  5. Console.WriteLine(bm.GetType().Name); 

输出结果如下:

 
 
 
  1. Path: e:\me.jpg  
  2. Type: Bitmap 

为了让大家更熟悉一下,再举一个实现数据结构中的二叉树作例子。

传统的树节点类,无论无论C/C++/Java都是类似这样:

 
 
 
  1. class TreeNode  
  2. {  
  3.     public TreeNode LeftChild { get; set; }  
  4.     public TreeNode RightChild { get; set; }  
  5.     public TreeNode Parent { get; set; }  
  6.     public int Value { get; set; }  

大家知道,二叉树又分好几种,AVL树、B树、红黑树等等。实现特殊的二叉树数据结构,势必要继承TreeNode。由于树节点的类型中,有类型为基类的成员,所以在子类操作这些成员时,往往也要强制转换类型,这比Image和WebRequest的例子,只在实例创建时转换类型还麻烦。

这就该泛型模式一显身手的好机会了,请看其父类型的实现:

 
 
 
  1. /// Type of the node.  
  2. /// Type of the node value.  
  3. class TreeNode where T:TreeNode where K: IComparable  
  4. {  
  5.     public T LeftChild { get; set; }  
  6.     public T RightChild { get; set; }  
  7.     public T Parent { get; set; }  
  8.     public K Value { get; set; }  

之后,实现任何一种特殊二叉树结构,比如RBTreeNode代表红黑树节点,可以这样:

 
 
 
  1. class RBTreeNode : TreeNode  
  2. {  
  3.     ///   
  4.     /// 树节点颜色,是否为红。  
  5.     ///   
  6.     public bool IsRed { get; set; }  
  7.  
  8.     public override string ToString()  
  9.     {  
  10.         return this.Value + "," + (this.IsRed ? "R" : "B");  
  11.     }  

这个是AVL树:

 
 
 
  1. class AvlTreeNode : TreeNode  
  2. {  
  3.     ///   
  4.     /// 节点的平衡度  
  5.     ///   
  6.     public int Balance { get; set; }  
  7.  
  8.     public override string ToString()  
  9.     {  
  10.         return "Balance: " + Balance + ", Value: " + this.Value;  
  11.     }  

不但完全符合OCP原则,而且再也不需要as来强制转换节点类型了。

这肯定不是我的首创,其实.NET Framework中已经不少这样的设计,比如IComparable接口。也有不少优秀的框架采用了类似的设计,比如大石头同学的ORM框架NewLife.XCode。

看上去也很简单吧,但是很多人思维还停留在面向对象语言刚诞生的阶段,还不习惯用这种设计模式。我认为这种写法足够典型和通用,足以得上一种设计模式,而且是.NET特殊优势,独特魅力。

说到设计模式,其实GOF提出的23种设计模式多年了,已经过时,出现了许多新模式(比如并发编程方面,参考Wiki Design Pattern)。旧有的模式中,有的已经包含在.NET语言特性中,有的模式实现方式已经改头换面。尤其在泛型出现后,许多模式的实现可以变得简洁许多,优雅许多。

不要一遍遍炒过去的冷饭,设计模式应该与时俱进,永远是充满新鲜活力的话题。

原文来自:http://www.cnblogs.com/XmNotes/archive/2012/04/23/2466938.html

【编辑推荐】

  1. 为什么我不再做.NET开发
  2. 详细解读ASP.NET的异步
  3. ASP.NET的路由系统:URL与物理文件的分离
  4. ASP.NET MVC3 从零开始一步步构建Web
  5. Node.js vs Opa: Web框架杀手

新闻标题:浅谈.NET独有精巧泛型设计模式
本文来源:http://www.shufengxianlan.com/qtweb/news32/246532.html

网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等

广告

声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联