zoukankan      html  css  js  c++  java
  • 什么是依赖注入

    1 定义

    依赖注入(Dependency Injection),简称DI,类之间的依赖关系由容器来负责。简单来讲a依赖b,但a不创建(或销毁)b,仅使用b,b的创建(或销毁)交给容器。

    2 例子

    为了把DI讲清楚,我们需要举一个简单例子。例子足够小,希望让你能直观的了解DI而不会陷入真实示例的泥潭。

    例子:小明要杀怪,那小明拿什么武器杀怪呢?可以用刀、也可以用拳头、斧子等。

    首先,我们创建一个演员类,名字叫“小明”,具有杀怪功能。

    namespace NoInjection.ConsoleApp
    {
        public class Actor
        {
            private string name = "小明";
            public void Kill()
            {
                var knife = new Knife();
                knife.Kill(name);
            }
        }
    }
    

    然后,我们再创建一个武器-刀类,具有杀怪功能。

    using System;
    
    namespace NoInjection.ConsoleApp
    {
        public class Knife
        {
            public void Kill(string name)
            {
                Console.WriteLine($"{name}用刀杀怪");
            }
        }
    }
    

    最后,我们客户端调用演员类,执行杀怪功能。

    using System;
    
    namespace NoInjection.ConsoleApp
    {
        class Program
        {
            static void Main(string[] args)
            {
                var actor = new Actor();
                actor.Kill();
    
                Console.ReadKey();
            }
        }
    }
    

    让我们来看看输出结果:

    小明用刀杀怪
    

    通过这个例子我们可以看到,Actor类依赖Knife类,在Actor中创建Knife,执行Knife.Kill方法。我们可以回顾一下DI的定义,a依赖b,但a不创建(或销毁)b,仅使用b,显然这个不符合DI做法。

    DI下面我们详细说说DI的几种形式。

    3 形式

    3.1 构造函数注入

    首先,我们在Actor通过构造函数传入Knife。

    namespace ConstructorInjection.ConsoleApp
    {
        public class Actor
        {
            private string name = "小明";
            private Knife knife;
            public Actor(Knife knife)
            {
                this.knife = knife;
            }
    
            public void Kill()
            {
                knife.Kill(name);
            }
        }
    }
    

    然后,Knife类不需要变化。

    using System;
    
    namespace ConstructorInjection.ConsoleApp
    {
        public class Knife
        {
            public void Kill(string name)
            {
                Console.WriteLine($"{name}用刀杀怪");
            }
        }
    }
    

    最后,我们客户端来创建Actor和Knife,然后在Actor通过构造函数传入Knife。

    using System;
    
    namespace ConstructorInjection.ConsoleApp
    {
        class Program
        {
            static void Main(string[] args)
            {
                var knife = new Knife();
                var actor = new Actor(knife);
                actor.Kill();
    
                Console.ReadKey();
            }
        }
    }
    

    让我们来看看输出结果:

    小明用刀杀怪
    

    这个例子我们可以看到,Actor类依赖Knife类,但在Actor不创建Knife,而是通过构造函数传入Knife。

    3.2 Setter注入

    首先,我们在Actor类创建Knife属性。

    namespace SetterInjection.ConsoleApp
    {
        public class Actor
        {
            private string name = "小明";
            private Knife knife;
            public Knife Knife
            {
                set 
                {
                    this.knife = value;
                }
                get
                {
                    return this.knife;
                }
            }
    
            public void Kill()
            {
                knife.Kill(name);
            }
        }
    }
    

    然后,Knife类不需要变化。

    using System;
    
    namespace SetterInjection.ConsoleApp
    {
        public class Knife
        {
            public void Kill(string name)
            {
                Console.WriteLine($"{name}用刀杀怪");
            }
        }
    }
    

    最后,我们客户端来创建Actor和Knife,然后在Actor通过属性传入Knife。

    using System;
    
    namespace SetterInjection.ConsoleApp
    {
        class Program
        {
            static void Main(string[] args)
            {
                var knife = new Knife();
                var actor = new Actor();
                actor.Knife = knife;
                actor.Kill();
    
                Console.ReadKey();
            }
        }
    }
    

    让我们来看看输出结果:

    小明用刀杀怪
    

    这个例子我们可以看到,Actor类依赖Knife类,但在Actor不创建Knife,而是通过属性传入Knife。

    3.3 接口注入

    首先,我们在Actor类创建Knife属性并继承IActor

    namespace InterfaceInjection.ConsoleApp
    {
        interface IActor
        {
            Knife Knife { set; get; }
            void Kill();
        }
    }
    
    namespace InterfaceInjection.ConsoleApp
    {
        public class Actor: IActor
        {
            private string name = "小明";
            private Knife knife;
            public Knife Knife
            {
                set 
                {
                    this.knife = value;
                }
                get
                {
                    return this.knife;
                }
            }
    
            public void Kill()
            {
                knife.Kill(name);
            }
        }
    }
    

    然后,Knife类不需要变化。

    using System;
    
    namespace InterfaceInjection.ConsoleApp
    {
        public class Knife
        {
            public void Kill(string name)
            {
                Console.WriteLine($"{name}用刀杀怪");
            }
        }
    }
    

    最后,我们客户端来创建Actor和Knife,然后在Actor通过属性传入Knife。

    using System;
    
    namespace InterfaceInjection.ConsoleApp
    {
        class Program
        {
            static void Main(string[] args)
            {
                var knife = new Knife();
                IActor actor = new Actor();
                actor.Knife = knife;
                actor.Kill();
    
                Console.ReadKey();
            }
        }
    }
    

    接口注入方式我理解了也不是很透,感觉跟Setter注入没有什么大的差别,只是增加了一个接口定义。

  • 相关阅读:
    Oracle数据库入门——体系结构
    基础知识——CentOS7操作系统的安装图文教程
    Oracle数据库入门——基础知识
    Windows Server 2008 R2 64位操作系统安装Oracle 11g 64位数据库,在客户终端上安装Oracle 11g 32位,才能安装P/L Sql Developer并配置
    2. Mysql数据库的入门知识
    1. Mysql数据库的安装
    Excel制作考勤管理
    常用函数公式及技巧搜集
    调试C++NPv2_Select_Reactor_Log_Server程序
    调试C++NPv2_Reactor_Log_Server程序
  • 原文地址:https://www.cnblogs.com/zcqiand/p/14257641.html
Copyright © 2011-2022 走看看