• 控制反转(Ioc)和依赖注入(DI)整理(二)(含代码示例)


     

    既然说在控制反转中获取资源的过程叫做依赖注入,那么这里代码实现也是专注于依赖注入。IoC实现的方式由两种: 依赖获取和依赖注入。

    接下来就细看依赖注入和依赖获取。

     

    三 . 依赖注入背景及定义 

     

         (http://blog.csdn.net/commandbaby/article/details/51578699)

       3.1. 背景

              随着面向对象分析与设计的发展,一个良好的设计,核心原则之一就是将变化隔离,使得变化部分发生变化时,不变部分不受影响(OCP)。为了做到这一点,要利用面向对象中的多态性,使用多态性后,客户类不再直接依赖服务类,而是依赖一个抽象的接口,这样,客户类就不能在内部直接实例化具体的服务类。但是,客户类在运行中又客观需要具体的服务类提供服务,因为接口是不能实例化去提供服务的。就产生了“客户类不准实例化具体服务类”和“客户类需要具体服务类”这样一对矛盾。为了解决这个矛盾,开发人员提出了一种模式:客户类定义一个注入点,用与服务类的注入,而客户类的客户类负责根据情况,实例化服务类,注入到客户类中,从而解决了这个矛盾。

        定义: 是这样一个过程:由于某客户类只依赖于服务类的一个接口,而不依赖于具体服务类,所以客户类只定义一个注入点。在程序运行过程中,客户类不直接实例化具体服务类实例,而是客户类的运行上下文环境或者专门负责实例化服务类,然后将其注入到客户类中,保证客户类的正常运行。

     

       3.2. 依赖注入类型

            3.2.1. Setter注入

            定义:是指在客户类中,设置一个服务类接口类型的数据成员,并设置一个Set方法作为注入点,这个Set方法接受一个具体的服务类实例为参数,并将它赋给服务类接口类型的数据成员。

     

     

    图3.1 Setter注入示意

     

        实例代码如下:  构建了一个服务类接口(IStudentInj),和两个实现接口的服务类(StudentA,StudentB). 定义了一个客户类GetStudentInfo.

        服务类接口(IStudentInj)的代码如下:

     public interface IStudentInj
        {
            void StudentName();
        }

     

     两个服务类代码如下:

    public class StudentA :IStudentInj
        {
            public void StudentName()
            {
                Console.WriteLine("I am student A!");
            }
        }
    
    
    public class StudentB : IStudentInj
        {
            public void StudentName()
            {
                Console.WriteLine("I am student B!");
            }
        }

     

     客户类代码:

     public class GetStudentInfo
        {
            IStudentInj stu;
    
            public void SetStudent(IStudentInj student)
            {
                this.stu = student;   
            }
    
            public void GetStudentName()
            {
                stu.StudentName();
            }
        }
    View Code

     

    测试代码:

    static void Main(string[] args)
            {
                GetStudentInfo getStu = new GetStudentInfo();
    
                getStu.SetStudent(new StudentA());
    
                getStu.GetStudentName();
    
                getStu.SetStudent(new StudentB());
    
                getStu.GetStudentName();
    
                Console.ReadLine();
            }

     

    测试结果:

     

        3.2.2. 构造注入

                   定义:是指在客户类中,设置一个服务类接口类型的数据成员,并以构造函数为注入点,这个构造函数接受一个具体的服务类实例为参数,并将它赋给服务类接口类型的数据成员。                                                       

     

    图3.3 构造注入示意

          图3.3是构造注入的示意图,可以看出,与Setter注入很类似,只是注入点由Setter方法变成了构造方法。这里要注意,由于构造注入只能在实例化客户类时注入一次,所以一点注入,程序运行期间是没法改变一个客户类对象内的服务类实例的。 

    由于构造注入同Setter注入相似,此处只给出客户类和测试代码:

    客户类代码:

    public class GetStudentInfo
        {
            IStudentInj stu;
    
            public GetStudentInfo(IStudentInj student)
            {
                this.stu = student;
            }
          
            public void GetStudentName()
            {
                stu.StudentName();
            }
        }
    View Code

     

    测试代码:

     class Program
        {
            static void Main(string[] args)
            {
                GetStudentInfo stu = new GetStudentInfo(new StudentA());
    
                stu.GetStudentName();
                
                Console.ReadLine();
            }
        }
    View Code

     

    测试结果:

     

    四. 依赖获取

    上面提到的注入方式,都是客户类被动接受所依赖的服务类,这也符合“注入”这个词。不过还有一种方法,可以和依赖注入达到相同的目的,就是依赖获取。

    依赖获取(Dependency Locate)是指在系统中提供一个获取点,客户类仍然依赖服务类的接口。当客户类需要服务类时,从获取点主动取得指定的服务类,具体的服务类类型由获取点的配置决定。

    可以看到,这种方法变被动为主动,使得客户类在需要时主动获取服务类,而将多态性的实现封装到获取点里面。获取点可以有很多种实现,也许最容易想到的就是建立一个Simple Factory作为获取点,客户类传入一个指定字符串,以获取相应服务类实例。如果所依赖的服务类是一系列类,那么依赖获取一般利用Abstract Factory模式构建获取点,然后,将服务类多态性转移到工厂的多态性上,而工厂的类型依赖一个外部配置,如XML文件。

    不过,不论使用Simple Factory还是Abstract Factory,都避免不了判断服务类类型或工厂类型,这样系统中总要有一个地方存在不符合OCP的if…else或switch…case结构,这种缺陷是Simple Factory和Abstract Factory以及依赖获取本身无法消除的,而在某些支持反射的语言中(如C#),通过将反射机制的引入彻底解决了这个问题(后面讨论)。

    4.2 .反射与依赖注入

    利用反射+配置文件解决上述的问题。

    具体的实例以后再补。

     

  • 相关阅读:
    ASP.NET Core 使用Redis存储Session
    JS复制文本到剪切板
    Linux 升级修改libc gcc 文件名称,导致执行命令失效问题解决
    Linux 基础命令-CURL 表单上传文件
    CentOS 下部署 ASP.NET Core环境
    ASP.NET Core 添加日志NLog
    Windows 下TortoiseGit 设置避免每次登录帐号密码
    类加载机制与双亲委派
    句子的成分
    词的作用
  • 原文地址:https://www.cnblogs.com/erhanhan/p/7678824.html
Copyright © 2020-2023  润新知