依赖注入

发布时间 2024-01-11 15:30:12作者: LiviaYu

依赖注入是什么

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

引入依赖注入的目的是为了解耦。说白了就是面向接口编程,通过调用接口的方法,而不直接实例化对象去调用。
这样做的好处就是如果添加了另一个实现类,不需要修改之前代码,只需要修改注入的地方将实现类替换。
上面说的通过接口调用方法,实际上还是需要去实例化接口的实现类,只不过不需要我们手动new 构造实现类,
而是交给如微软的DI、Autofac这些工具去构建实现类。我们只需要告诉它们,某个类是某个接口的实现类,
当用到的时候,工具(比如,微软的DI)会自动通过构造函数实例化类。

a只是去使用b,并不去创建b,从而降低代码的耦合性

代码耦合性过高

首先有一个小明,它可以杀怪

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

然后有一个knife类,具有杀怪的功能

using System;

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

最后调用actor实现杀怪

using System;

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

            Console.ReadKey();
        }
    }
}

当前的输出就是小明用刀杀怪

依赖注入的方式

构造函数注入

组件的依赖通过构造函数参数进行注入
在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类不变
然后主逻辑中创建actor和knife,通过构造函数传入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。

Setter 方法注入(Setter Injection

组件提供 Setter 方法,通过这些方法注入依赖。

Actor中创建setter方法

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类同样不变
主逻辑创建actor和knife,并且通过actor的提供的setter方法拿到这把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。

接口注入(Interface Injection):

组件实现一个接口,并通过接口方法接收依赖。

看不懂