好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

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

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

在.NET发展史中,2.0是具有里程碑意义的一个版本。从这个版本,.NET青出于蓝(Java),而胜于蓝。在.NET 2.0带来的诸多新特性中,我认为泛型是最重要,没有之一。

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

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

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

或者这么写,也是一样:

 var  request =  HttpWebRequest .Create( "http://www.cnblogs.com/" )  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

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

大家知道,二叉树又分好几种,AVL树、B树、红黑树等等。由于树节点的类型中,有类型和自己相同的成员,所以是泛型模式一显身手的好机会。其父类型的实现:

 /// <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 , Int32 >
{
     /// <summary>
    ///   树节点颜色,是否为红。
      /// </summary>
      public bool  IsRed {  get ;  set ; }

     public override string  ToString()
    {
         return this .Value +  ","  + ( this .IsRed ?  "R"  :  "B" );
    }
}

这个是AVL树:

 class   AvlTreeNode  :  TreeNode < AvlTreeNode , Int32 >
{
     /// <summary>
    ///   节点的平衡度
      /// </summary>
      public int  Balance {  get ;  set ; }

     public override string  ToString()
    {
         return   "Balance: "  + Balance +  ", Value: "  +  this .Value;
    }
}

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

看上去很简单吧,其实.NET Framework中已经不少这样的设计,比如IComparable<T>接口,但是很多人思维还停留在面向对象语言刚诞生的阶段,还不习惯用这种设计模式。我认为这种写法足够典型和通用,足以得上一种设计模式。

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

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

作者: Leo_wl

    

出处: http://www.cnblogs.com/Leo_wl/

    

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

版权信息

查看更多关于.NET独有的精巧泛型设计模式的详细内容...

  阅读:48次