• 复用离不开反射和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泛型方法来实现。

     
    分类: 系统架构
  • 相关阅读:
    项目实施(一)
    比较2个DataTable中的内容是否相同的方法
    [三、页面布局]18使用ScrollView在限定的区域显示超长的内容
    [三、页面布局]14使列表同时支持删除和移动记录的功能
    [三、页面布局]15使用Section将列表氛围几个组
    [三、页面布局]13调整记录在List列表里的顺序
    [三、页面布局]22制作一份漂亮而强大的表单
    [三、页面布局]16使用tintColor单独设置列表中的图表颜色
    [三、页面布局]20创建两层嵌套的滚动视图
    [三、页面布局]19创建一个水平方向上的滚动视图
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/2533070.html
Copyright © 2020-2023  润新知