什麼是依賴注入

1 定義

依賴注入(Dependency Injection),簡稱DI,類之間的依賴關係由容器來負責。簡單來說a依賴b,但a不建立(或銷燬)b,僅使用b,b的建立(或銷燬)交給容器。函數

2 例子

爲了把DI講清楚,咱們須要舉一個簡單例子。例子足夠小,但願讓你能直觀的瞭解DI而不會陷入真實示例的泥潭。this

例子:小明要殺怪,那小明拿什麼武器殺怪呢?能夠用刀、也能夠用拳頭、斧子等。spa

首先,咱們建立一個演員類,名字叫「小明」,具備殺怪功能。code

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();
        }
    }
}

讓咱們來看看輸出結果:get

小明用刀殺怪

經過這個例子咱們能夠看到,Actor類依賴Knife類,在Actor中建立Knife,執行Knife.Kill方法。咱們能夠回顧一下DI的定義,a依賴b,但a不建立(或銷燬)b,僅使用b,顯然這個不符合DI作法。string

DI下面咱們詳細說說DI的幾種形式。it

3 形式

3.1 構造函數注入

首先,咱們在Actor經過構造函數傳入Knife。io

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

相關文章
相關標籤/搜索