什么是依賴注入


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注入沒有什么大的差別,只是增加了一個接口定義。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM