天天看點

依賴倒置原則 個人了解

1.依賴倒置原則:(DIP)高層子產品不應依賴底層子產品,兩者都應依賴抽象。

     為什麼依賴注入? 為了實作控制反轉.

     為什麼控制反轉? 我們的軟體設計需要符合依賴倒置原則.

2.依賴注入(DI)  控制反轉(IOC)(技術手段)

   ·IOC容器,依賴注入,IOC控制反轉的關系

        依賴注入,反轉依賴的!因為有了依賴注入,才有了控制反轉; 

         即先有容器再有依賴注入,最後才有控制反轉。

    IOC容器,依賴注入架構的東西提供的。映射依賴、管理對象建立和生命周期;再也不用New,有人幫你new。

場景例子:假設你是一個五歲的小孩,你餓了就要吃,需求。怎麼找吃的?

      1.找吃的 直接從冰箱拿

      2.找媽媽要   父母(IOC容器)會給你做食物,然後拿給你(注入)

   從你想吃東西的需求,從主動去冰箱(正轉)拿食物,到想吃的食物而被動獲得(反轉),即媽媽做

   控制反轉:元件對象控制權的轉移。類型A(小孩)中需要使用類型B(食物),這個B的建立并不由A來負責,而是由第三方(媽媽)建立。

   IOC一種反轉流、依賴和接口的方式,他把傳統上由程式代碼直接操控的對象的調用權交給第三方(容器),通過第三方來實作對象元件的配置和管理。

場景:父親給孩子講故事,隻要給父親一本書,他就可以照着書給孩子将故事。

  1.不經過任何設計模式和設計原則加工的傳統的OOP方式,強依賴,以利于擴充。

namespace FatherStoryCustom
{
    /// <summary>
    /// 場景:父親給孩子講故事,隻要給父親一本書,他就可以照着書給孩子将故事。
    /// 
    /// 不經過任何設計模式和設計原則加工的傳統的OOP方式。。
    /// </summary>
    class Program
    {
        static void Main(string[] args)
        {
            Father father = new Father();
            father.Read();

            Console.ReadKey();
        }
    }

    public class Book
    {
        public string GetContent()
        {
            return "從前有座山,山上有座廟.....";
        }
    }

    public class Father
    {
        public void Read()
        {
            Book book = new Book();
            Console.WriteLine("爸爸開始講故事啦..");
            Console.WriteLine(book.GetContent());
        }
    }

}
           

場景:父親給孩子講故事,隻要給父親一本書,他就可以照着書給孩子将故事。

有一天需求變了,不給書了,給報紙,讀報紙上的新聞。

2.通過工廠模式來實作,但還是需要在工廠中建立對象

namespace FatherStoryDIP
{
    /// <summary>
    /// 場景:父親給孩子講故事,隻要給父親一本書,他就可以照着書給孩子将故事。
    /// 有一天需求變了,不給書了,給報紙,讀報紙上的新聞。
    /// 上一個普通做法耦合太強,父親太依賴書了。
    /// </summary>
    class Program
    {
        static void Main(string[] args)
        {
            // 工廠模式建立對象
            Father father = new Father("Paper");

            Console.ReadKey();
        }
    }

    /// <summary>
    /// 讀物的接口
    /// </summary>
    public interface IReader
    {
        string GetContent();
    }

    public class Paper : IReader
    {
        public string GetContent()
        {
            return "王思聰被限制消費..";
        }
    }

    public class Book : IReader
    {
        public string GetContent()
        {
            return "從前有座山,山上有座廟...";
        }
    }

    public class Father
    {
        private IReader _reader { get; set; }
        // 工廠模式建立對象
        public Father(string readerName)
        {
            _reader = ReaderFactory.GetReader(readerName);
        }

        public void Read()
        {
            Console.WriteLine("爸爸給孩子開始講故事了..");
            Console.WriteLine(_reader.GetContent());
        }
    }
}
           
namespace FatherStoryDIP
{
    public static class ReaderFactory
    {
        public static IReader GetReader(string readType)
        {
            if (string.IsNullOrEmpty(readType))
            {
                return null;
            }

            switch (readType)
            {
                case "Paper":
                    return new Paper();
                case "Book":
                    return new Book();
                default:
                    return null;
            }
        }
    }
}
           

3.和上面2的場景一樣,通過依賴注入來建立對象。将上面2的代碼進行再更新。

工廠模式 =>更新=> IOC容器的基礎

IOC容器,一個自動化的工廠,還帶配送,要什麼給什麼。徹底的解耦,高層不依賴于低層,依賴抽象。

namespace FatherStoryDIP
{
    /// <summary>
    /// 場景:父親給孩子講故事,隻要給父親一本書,他就可以照着書給孩子将故事。
    /// 有一天需求變了,不給書了,給報紙,讀報紙上的新聞。
    /// </summary>
    class Program
    {
        static void Main(string[] args)
        {
            // 通過容器建立對象
            var sc = new ServiceCollection();
            // 接口對應執行個體進行注冊
            //sc.AddScoped(typeof(IReader), typeof(Book));
            //var sp = sc.BuildServiceProvider();
            //IReader reader = sp.GetService<IReader>();
            //Father father = new Father(reader);
            //father.Read();

            // Unity建立容器 全程沒有new對象
            var container = new UnityContainer();
            container.RegisterType<IReader, Book>();
            container.RegisterType<Father>();
            // 解析容器中的對象,用什麼泛型中填什麼
            var father = container.Resolve<Father>();
            father.Read();
            Console.ReadKey();
        }
    }

    /// <summary>
    /// 讀物的接口
    /// </summary>
    public interface IReader
    {
        string GetContent();
    }

    public class Paper : IReader
    {
        public string GetContent()
        {
            return "王思聰被限制消費..";
        }
    }

    public class Book : IReader
    {
        public string GetContent()
        {
            return "從前有座山,山上有座廟...";
        }
    }

    public class Father
    {
        private IReader _reader { get; set; }

        public Father(IReader reader)
        {
            _reader = reader;
        }

        public void Read()
        {
            Console.WriteLine("爸爸給孩子開始講故事了..");
            Console.WriteLine(_reader.GetContent());
        }
    }
}
           

 容器類似于一個登記本,生産的東西登記到容器中,用的時候直接從容器中取。

            目前代碼用寫死的方式注冊,注冊類型的方式有很多種

                1.配置檔案,動态加載

               2.批量注冊,将特殊辨別的實體類(例:字尾為Service或者有某個特性)的全部注冊到容器中

               3.通過反射,掃描程式集,找到你想要找到的類注冊進來。例如字尾名為Service