zoukankan      html  css  js  c++  java
  • 复用离不开反射和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泛型方法来实现。

     
    分类: 系统架构
  • 相关阅读:
    一行代码更改博客园皮肤
    fatal: refusing to merge unrelated histories
    使用 netcat 传输大文件
    linux 命令后台运行
    .net core 使用 Nlog 配置文件
    .net core 使用 Nlog 集成 exceptionless 配置文件
    Mysql不同字符串格式的连表查询
    Mongodb between 时间范围
    VS Code 使用 Debugger for Chrome 调试vue
    css权重说明
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/2533070.html
Copyright © 2011-2022 走看看