好得很程序员自学网

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

复用离不开反射和IOC

复用离不开反射和IOC

现在就让我们一起来看一下什么是多态以及如何实现多态。

       多态就是不同的对象收到相同的消息时会产生不同的行为。同一个类在不同的场合下表现出不同的行为特征。

       多态的作用:把不同的子类对象当做父类来看,可以屏蔽不同的子类对象之间的差异,写出通用的代码,做出通用的编程,增加程序的灵活性和可扩展性,以适应需求的不断变化。

       如何实现多态呢?

       首先实现多态的条件就是继承(或实现接口)。实现多态的方式可以有以下三种方式:

       1、父类成员用virtual关键字修饰,子类可以重写父类成员(此处所指的成员均为子类可以继承的成员)

       2、父类成员用abstract关键字修饰,子类可以重写父类的成员而且必须重写(最终)。

       3、实现接口,子类可以实现接口中定义的方法而且必须实现。

       一、使用virtual实现多态

       用virtual修饰的方法称为虚方法。

       1、当父类有方法需要让子类重写时,则可以将此方法标记为virtual。

       2、虚方法在父类中必须要给出实现,哪怕是空实现。

       3、子类可以重写父类的虚方法,也可以不重写。

       下面我们就来看一个小例子:

  1           static   void  Main( string  [] args)
   2           {
   3               object  str =  "  你好  "  ;
   4               object  person =  new  Person() { Name= "  张三  "   };
   5              Console.WriteLine(str.ToString());              //  此处输出什么? 
  6              Console.WriteLine(person.ToString());   //  此处输出什么? 
  7               Console.ReadKey();
   8           }
   9  
 10           public   class   Person
  11           {
  12               public   string   Name
  13               {
  14                   get  ;
  15                   set  ;
  16               }
  17          }

         聪明的你是不是已经知道了输出的结果呢?没错,第一行输出“你好”,第二行输出“命名空间.Person”,其中的命名空间据你的项目而定,同样都是object对象,为什么会出现这种情况呢?要解决这个问题,我们先得了解一下ToString()方法。
         ToString()是object类定义的一个虚方法,其实现的功能为把当前对象的类型装换为字符串输出。那么第一行为什么没有输出对象的类型呢?以为string类重写了ToString()方法,把当前对象输出了(即把string对象本身输出)。由于Person类没有重写ToString()方法,所以输出的是当前对象的类型。

         下面我们把Person类的代码稍稍改动一下。

         public   class   Person
        {
              public   string   Name
            {
                  get  ;
                  set  ;
            }

              public   override   string   ToString()
            {
                  return   this  .Name;
            }
        } 

        此时第二行就会输出“张三”。

        二、使用abstract实现多态

       先来看一下有关抽象类的相关概念:

        1、abstract关键字不光可以修饰类成员,还可以修饰类。被abstract修饰的类称为抽象类,被abstract修饰的方法称为抽象方法。

        2、抽象类不能被实例化,如果要想实例化,则必须有子类继承他,并且抽象类变量只能指向实现了他中的所有抽象成员的子类对象。

        3、抽象类的子类如果没有实现他的抽象方法,或者只是实现了一部分,则这个类也必须是抽象类。

        4、如果一个类中包含抽象方法,则这个类必须声明为抽象类。反之,抽象类中不一顶含有抽象方法。

        5、抽象方法必须不能给出任何实现。

        6、抽象类既可以包含抽象成员,又可以包含具体代码成员。

        7、抽象类不能用static或sealed修饰。抽象方法不能用static或private修饰。

        8、抽象类中有构造函数,而且可以重载。

        说了好多,我都有点凌乱了,哈哈……

        记得曾经有人和我争论一个问题,说抽象类可以不被子类继承(很纠结的问题),这句话百分之百是对的,但是我们在项目中定义一个抽象类,而不用子类去继承他,那么它的存在还有什么意义呢?既然我们定义了抽象类,说明我们一定要用他,既然要用它就必须要有子类继承他(因为他本身不能被实例化)。(个人观点,有些偏激)

        下面我们来做一个抽象类的小例子:

        “橡皮鸭子(RubberDuck)、真实的鸭子(RealDuck)。两个鸭子都会游泳,而橡皮鸭子和真实的鸭子都会叫,只是叫声不一样,橡皮鸭子“唧唧”叫,真实地鸭子“嘎嘎”叫”

         public   abstract   class   Duck
        {
              public   string   Name
            {
                  get  ;
                  set  ;
            }

              public   void   Swim()
            {
                Console.WriteLine(  "  我是{0},I can swimming!  " , this  .Name);
            }

              public   abstract   void   Speek();

        }

          public   class   RubberDuck:Duck
        {
              public  RubberDuck( string   name)
            {
                  this .Name =  name;
            }

              public   override   void   Speek()
            {
                Console.WriteLine(  "  唧唧...  "  );
            }
        }

          public   class   RealDuck : Duck
        {
              public  RealDuck( string   name)
            {
                  this .Name =  name;
            }

              public   override   void   Speek()
            {
                Console.WriteLine(  "  嘎嘎...  "  );
            }
        }

          static   void  Main( string  [] args)
        {
            Duck duck1  =  new  RubberDuck( "  RubberDuck  "  );
            Duck duck2  =  new  RealDuck( "  RealDuck  "  );
            duck1.Swim();
            duck1.Speek();
            duck2.Swim();
            duck2.Speek();
            Console.ReadKey();
        } 

          至于输出结果,大家在脑子中输出一下吧。。。

          三、使用接口实现多态

          神马是接口?

          接口就是一种规范,一种协议,约定好遵守某种协议就可以写出通用的代码。

          1、接口中定义了若干个具有各自功能的方法,只是表示一种能力,并没有具体实现。

          2、接口中的成员不能有访问修饰符,默认public。

          3、接口中可以有属性,方法,索引器,事件等(归根结底都是方法),但是不能有字段(可以有静态)。

          4、实现接口的子类必须实现该接口的全部成员。(直接子类)

          5、一个类可以同时实现多个接口,接口也可以继承接口。

          6、接口不能被实例化。

          7、如果继承接口的类不想全部实现接口中的成员,则可以把这个类声明为抽象类,把不实现的方法声明为抽象方法。

          8、如果一个类同时继承了类和实现了接口,则必须把类放在前面。

          是不是又凌乱了呢?好吧,先说这么多吧。

          有时候我们总是觉得既然有了抽象类,还要接口做什么呢?其实接口是有他的存在意义的。比如我们看下面的例子:

          “一架直升飞机和一只麻雀都会飞,但是一架直升飞机属于飞机类,一只麻雀属于鸟类,飞机不具备鸟类的共有属性,同理,鸟类也不具有飞机类的共有特性,因此他们不能抽象一个共有的父类(否则从他们的父类派生的子类就会同时具备飞机和鸟类的全部特性,这会造成子类冗余)。那么在这种情况下,我们要想对”飞“这个能力实现多态,该怎么办呢?对,用接口。

         public   class   Plane
        {
              public   string   Name
            {
                  set  ;
                  get  ;
            }

              public   void   LoadPeople()
            {
                Console.WriteLine(  "  我可以载人  "  );
            }
        }

          public   class   Bird
        {
              public   string   Name
            {
                  set  ;
                  get  ;
            }

              public   void   Raise()
            {
                Console.WriteLine(  "  我可以繁殖后代  "  );
            }
        }

          public   interface   IFlyable
        {
              void   Fly();
        }

          public   class   VertiPlane:Plane,IFlyable
        {
               public   void   Fly()
             {
                 Console.WriteLine(  "  我是{0},I can Flying!  " , this  .Name);
             }
        }

          public   class   Sparrow : Plane, IFlyable
        {
              public   void   Fly()
            {
                Console.WriteLine(  "  我是{0},I can Flying!  " ,  this  .Name);
            }
        }
          static   void  Main( string  [] args)
        {
            IFlyable plane  =  new  VertiPlane() { Name= "  直升飞机  "  };
            IFlyable bird  =  new  Sparrow { Name =  "  麻雀  "   };
            plane.Fly();
            bird.Fly();
            Console.ReadKey();
        } 

           此时如果我们要用这两个对象的其他属性怎么办呢?可以显示转换为想要的类型(前提是他指向的对象必须是将要转换的类型)

从本文标题中可以看出,主要说的是反射技术和控制反转(IOC)技术,本文主要先介绍一下我对这两种技术的理解及它们的优缺点,最后再用实例来说一下使用方法。

反射:可以使用反射动态创建类型的实例,将类型绑定到现有对象,或从现有对象获取类型并调用其方法或访问其字段和属性。这里,它最重要的是“动态性”,即根据条件动态创建“指定类型”的“实例”。

 1   //   Using GetType to obtain type information: 
 2   int  i =  42  ;
  3  System.Type type =  i.GetType();
  4  System.Console.WriteLine(type);

结果是:

System.Int32

本示例使用静态方法  GetType( Object  基类派生的所有类型都继承该方法) 获取变量类型的简单反射实例

 1   //   Using Reflection to get information from an Assembly: 
 2  System.Reflection.Assembly o = System.Reflection.Assembly.Load( "  mscorlib.dll  "  );
  3  System.Console.WriteLine(o.GetName());

结果是:

mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089

本示例使用反射获取已加载的程序集的完整名称

反射一般用在以下情况中:

需要访问程序元数据的属性。linq to sql 中使用很多

执行后期绑定,访问在运行时创建的类型的方法。与工厂模式一起使用,根据配置文件中的类型来动态建立实例

IOC:(Inversion of Control,英文缩写为IoC)是一个重要的面向对象编程的法则来削减计算机程序的耦合问题。 控制反转还有一个名字叫做依赖注入(Dependency Injection)。简称DI。实现IOC的架构有很多如:Avalon 、Spring、JBoss及Unity等。

理解IOC:可以把IoC模式看做是工厂模式的升华,可以把IoC看作是一个大工厂,只不过这个大工厂里要生成的对象都是在XML文件中给出定义的,然后利用Java 的“反射”编程,根据XML中给出的类名生成相应的对象。

实现非常简单,根据容易名称去创建对象即可

  1       ///   <summary> 
  2       ///   The static factory of container
   3       ///   </summary> 
  4       public   sealed   class   ContainerManager
   5       {
   6           ///   <summary> 
  7           ///   Creates the specified container instance .
   8           ///   </summary> 
  9           ///   <param name="containerName">  Name of the container.  </param> 
 10           ///   <returns></returns> 
 11           public   static  IContainerContext GetContainer( string   containerName)
  12           {
  13               return   new   UnityContainerContext(containerName);
  14           }
  15      }

以下是在实际项目中的使用,IOC架构是用Unity,它的基础代码是:

   1       ///   <summary> 
   2       ///   The specific container context for Unity
    3       ///   </summary> 
   4       public   class   UnityContainerContext : ContainerContextBase
    5       {
    6           #region  Fields
   7  
   8           ///   <summary> 
   9           ///   The lock used for synchronous
   10           ///   </summary> 
  11           private   static   readonly   object  _synlock =  new   object  ();
   12  
  13           #endregion 
  14  
  15           #region  Constructor
  16  
  17           ///   <summary> 
  18           ///   Initializes a new instance of the   <see cref="UnityContainerContext"/>   class.
   19           ///   </summary> 
  20           ///   <param name="name">  The name.  </param> 
  21           public  UnityContainerContext( string   name)
   22              :  base  (name)
   23           {
   24           }
   25  
  26           #endregion 
  27  
  28           #region  Properties
  29  
  30           ///   <summary> 
  31           ///   Gets the current context.
   32           ///   </summary> 
  33           ///   <value>  The current context.  </value> 
  34           private   HttpContext CurrentContext
   35           {
   36               get 
  37               {
   38                  HttpContext context =  HttpContext.Current;
   39                   if  (context ==  null  )
   40                   {
   41                       throw   new  Exception( "  The current httpcontext is null  "  );
   42                   }
   43                   return   context;
   44               }
   45           }
   46  
  47           #endregion 
  48  
  49           #region  Override Methods
  50  
  51           ///   <summary> 
  52           ///   Initializes container.
   53           ///   </summary> 
  54           public   override   void   Initialize()
   55           {
   56              OnBeforeInitialized( new  ContainerEventArgs( this  , ContainerType.Unity));
   57  
  58               if  (CurrentContext.Application[Name] ==  null  )
   59               {
   60                   lock   (_synlock)
   61                   {
   62                       if  (CurrentContext.Application[Name] ==  null  )
   63                       {
   64                          IUnityContainer currentContainer =  new   UnityContainer();
   65                          UnityConfigurationSection section = ConfigurationManager.GetSection( "  unity  " )  as   UnityConfigurationSection;
   66                           section.Containers[Name].Configure(currentContainer);
   67                          CurrentContext.Application[Name] =  currentContainer;
   68                       }
   69                   }
   70               }
   71  
  72              OnAfterInitialized( new  ContainerEventArgs( this  , ContainerType.Unity));
   73           }
   74  
  75           ///   <summary> 
  76           ///   Resolves this instance.
   77           ///   </summary> 
  78           ///   <typeparam name="T">  Parameter type.  </typeparam> 
  79           ///   <returns></returns> 
  80           public   override  T Resolve<T> ()
   81           {
   82               try 
  83               {
   84                   Initialize();
   85  
  86                  IUnityContainer currentContainer = CurrentContext.Application[Name]  as   IUnityContainer;
   87                   return  currentContainer.Resolve<T> ();
   88               }
   89               catch  (Exception ex)
   90               {
   91                  OnResolveFailed( new  ContainerFailedEventArgs( this  , ContainerType.Unity, ex));
   92                   return   default  (T);
   93               }
   94           }
   95  
  96           ///   <summary> 
  97           ///   Tears down.
   98           ///   </summary> 
  99           public   override   void   TearDown()
  100           {
  101              OnBeforeTearDown( new  ContainerEventArgs( this  , ContainerType.Unity));
  102  
 103              CurrentContext.Application[Name] =  null  ;
  104  
 105              OnAfterTearDown( new  ContainerEventArgs( this  , ContainerType.Unity));
  106           }
  107  
 108           #endregion 
 109  
 110      }

在项目中通过unity来创建对象的代码是:

  1           ///   <summary> 
  2           ///   数据层实体的个性操作对象
   3           ///   </summary> 
  4           ///   <typeparam name="TEntity"></typeparam> 
  5           ///   <returns></returns> 
  6           protected  TEntity LoadRepositoryEntity<TEntity> ()
   7           {
   8              IContainerContext container = ContainerManager.GetContainer( "  repositoryContainer  "  );
   9               return  container.Resolve<TEntity> ();
  10          }

这样,在BLL层调用DAL层对象时,可以通过LoadRepositoryEntity泛型方法来实现。

 

分类:  系统架构

作者: Leo_wl

    

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

    

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

版权信息

查看更多关于复用离不开反射和IOC的详细内容...

  阅读:40次