什么是依赖注入

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

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值