• 什么是依赖注入


    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注入没有什么大的差别,只是增加了一个接口定义。

  • 相关阅读:
    面向对象编程
    面向对象编程进阶
    pycharm常用快捷键
    面向对象
    深拷贝和浅拷贝
    hashlib模块
    日志配置
    常用模块大全
    正则详解
    软件目录规范
  • 原文地址:https://www.cnblogs.com/zcqiand/p/14257641.html
Copyright © 2020-2023  润新知