淺談IOC

来源:http://www.cnblogs.com/jdzhang/archive/2017/07/02/7104351.html
-Advertisement-
Play Games

一、引言 IOC-Invertion of Control,即控制反轉,是一種程式設計思想,世上本沒有路,走的人多了便有了路,本文將一步步帶你瞭解IOC設計思想的演進之路。 在學習IOC之前我們先初步瞭解幾個概念 依賴(Dependency):就是有聯繫,表示一個類依賴於另一個類 依賴倒置原則(DI ...


一、引言

IOC-Invertion of Control,即控制反轉,是一種程式設計思想,世上本沒有路,走的人多了便有了路,本文將一步步帶你瞭解IOC設計思想的演進之路。

在學習IOC之前我們先初步瞭解幾個概念

依賴(Dependency):就是有聯繫,表示一個類依賴於另一個類

依賴倒置原則(DIP):設計模式六大原則之一,是一種軟體架構設計原則

控制反轉(IOC):一種軟體設計原則,上層對下層的依賴(即底層模塊的獲得)交給第三方

依賴註入(DI):實現IOC的一種方式、手段

IOC容器:依賴註入的框架,用來映射依賴,管理對象創建和生存周期

二、依賴

依賴就是有聯繫,有地方使用它就是有依賴它,下麵看一個簡單的示例

  class BMW
    {
        public string Show()
        {
            return "寶馬";
        }
    }
    class ChinesePeople
    {
        private BMW bmw = new BMW();
        public void Run()
        {
            Console.WriteLine($"今天開{bmw.Show()}上班");
        }
    }
     class Program
    {
        static void Main(string[] args)
        {
            ChinesePeople people = new ChinesePeople();
            BMW bmw = new BMW();
            people.Run();
            Console.Read();
        }
    }
View Code

上面中國人開著寶馬去上班,客戶端有使用中國人、寶馬汽車兩個對象,中國人中有使用對象寶馬汽車,我們可以從中找到三個依賴關係:

客戶端依賴對象ChinesePeople;

客戶端依賴對象BMW;

ChinesePeople依賴對象BMW;

三、依賴倒置原則

過些日子來了新需求,中國人不僅要開寶馬去上班,還要開賓士去上班,如果按照上面直接依賴關係的方式去做,我們就需要修改ChinesePeople類,讓它實現一個參數為寶馬的重載方法Run(),顯然這樣不是好的設計,我們總不能每次新增一種汽車(即修改下層模塊)都要去修改ChinesePeople類吧(相對於汽車為上層模塊),太麻煩了。。。

先簡單分析一下,耦合關係就是依賴關係,如果依賴關係很重,牽一發而動全身,將很難維護擴展,耦合關係越少,系統會越穩定,因此要較少依賴

定義:A.高層模塊不應依賴於底層模塊,兩者應該依賴於抽象

   B.抽象不應該依賴於細節,細節應該依賴於抽象

在這個圖中,我們發現高層模塊定義介面,將不直接依賴於下層模塊,下層模塊負責實現高層模塊定義的介面,下麵看代碼demo:

    interface ICar
    {
        string Show();
    }
    class BMW:ICar
    {
        public string Show()
        {
            return "寶馬";
        }
    }
     class BenZ : ICar
    {
        public string Show()
        {
            return "賓士";
        }
    }
    interface IPeople
    {
         void Run(ICar bmw);
    }
    class ChinesePeople :IPeople
    {
        public void Run(ICar bmw)
        {
            Console.WriteLine($"今天開{bmw.Show()}上班");
        }
    }
     class Program
    {
        static void Main(string[] args)
        {
            ICar carBMW = new BMW();
            ICar carBenZ = new BenZ();
            IPeople people = new ChinesePeople();
            people.Run(carBMW);
            people.Run(carBenZ);
            Console.Read();
        }
    }
View Code

分析:上面代碼中,ChinesePeople類不再依賴於具體的汽車,而是依賴於汽車的抽象,這樣使得不管換什麼樣的汽車品牌,中國人都是可以開著去上班的,而且不需要修改ChinesePeople類。想一下,這樣是不是挺好的,我們可以得出:上層不再依賴細節,相比面向實現,面向介面較好,因為抽象相比細節要更穩定。

四、控制反轉

上面示例中,我們實現了具體的人和具體的汽車的隔離,具體人只和汽車的介面有關。但是Program中main方法里的具體對象寫死了,控制權變小,當我要修改美國人開著福特去上班時,就不得不要去修改代碼,那怎麼把控制權轉移呢?

下麵看一個簡單的示例:

    interface ICar
    {
        string Show();
    }
    class BMW:ICar
    {
        public string Show()
        {
            return "寶馬";
        }
    }
    interface IPeople
    {
         void Run(ICar bmw);
    }
    class ChinesePeople :IPeople
    {
        public void Run(ICar bmw)
        {
            Console.WriteLine($"今天開{bmw.Show()}上班");
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            string people =     ConfigurationManager.AppSettings["people"];
            string car = ConfigurationManager.AppSettings["car"];
            Assembly assemblypeople = Assembly.Load(people.Split(',')[1]);
            Assembly assemblycar = Assembly.Load(car.Split(',')[1]);
            Type typepeople = assemblypeople.GetType(people.Split(',')[0]);
            Type typecar = assemblypeople.GetType(car.Split(',')[0]);
            IPeople ipeople= (IPeople)Activator.CreateInstance(typepeople);
            ICar icar = (ICar)Activator.CreateInstance(typecar);
            ipeople.Run(icar);
            Console.Read();
        }
    }

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
    </startup>
  <appSettings>
    <add key="people" value="MyIOC_IOC.ChinesePeople,MyIOC_IOC"/>
    <add key="car" value="MyIOC_IOC.BMW,MyIOC_IOC"/>
  </appSettings>
</configuration>
View Code

上面代碼中,我們使用反射+配置文件的方式,將對象創建的控制權轉移到了配置文件,這就是所謂的控制反轉

分析,控制反轉是將對象創建的控制權交給了第三方,可以是IOC容器,它就相當於工廠,我們要什麼對象,工廠給我們什麼對象,這樣依賴關係就變了,它們(人和車)都依賴於IOC容器,通過IOC容器建立它們之間的依賴關係。(依賴對象不再被依賴模塊的類中直接通過new來獲取)

五、依賴註入

上面說到的控制反轉,我們瞭解到是將控制權轉移,這是我們的目的,配置文件+反射是是一種實現,而依賴註入則提供的是一種思想,或者說是實現IOC的手段。

依賴註入是將對象的創建和綁定轉移到被依賴對象的外部來實現。在依賴關係中ChinesePeople類所依賴的對象BMW類的創建和綁定是在ChinesePeople類內部執行的,顯然這種方法是不可取的,那我們怎麼BMW類的引用傳遞給ChinesePeople類呢?

方法一 構造函數註入

     interface ICar
    {
        string Show();
    } 
    class BMW:ICar
    {
        public string Show()
        {
            return "寶馬";
        }
    }
     class ChinesePeopleContructor 
    {
        private ICar _car;
        public ChinesePeopleContructor(ICar bmw)
        {
            _car = bmw;
        }
        public void Run()
        {
            Console.WriteLine($"今天開{_car.Show()}上班");
        }
    }
    static void Main(string[] args)
        {
            ICar car = new BMW();
            ChinesePeopleContructor people = new ChinesePeopleContructor(car);
            people.Run();
            Console.Read();
        }
View Code

分析,BMW類對象的創建和綁定轉移到ChinesePeople類的外部來實現,解除了兩個對象之間的耦合,當需要開賓士去上班的時候,只需要定義一個賓士類,外部重新綁定依賴,不需要修改ChinesePeople類的內部,即可是先中國人開賓士去上班的需求

方法二 屬性註入

interface ICar
    {
        string Show();
    }
    class BMW:ICar
    {
        public string Show()
        {
            return "寶馬";
        }
    }
    class ChinesePeopleProperty
    {
        private ICar _ICar;
        public ICar IC
        {
            get { return _ICar; }
            set { _ICar = value; }       
        }
        public void Run()
        {
            Console.WriteLine($"今天開{_ICar.Show()}上班");
        }
    }
    static void Main(string[] args)
     {
         ICar car = new BMW();
         ChinesePeopleProperty people = new ChinesePeopleProperty();
         people.IC = car;
         people.Run();
         Console.Read();
     }
View Code

分析,屬性註入是通過給屬性賦值,從而傳遞依賴

方法三 介面註入

     interface ICar
    {
        string Show();
    }
     class BMW:ICar
    {
        public string Show()
        {
            return "寶馬";
        }
    }
     interface IDependent
    {
        void SetDependent(ICar icar);
    }
    class ChinesePeopleInterface : IDependent
    {
        private ICar _ICar;
        public void SetDependent(ICar icar)
        {
            _ICar = icar;
        }
        public void Run()
        {
            Console.WriteLine($"今天開{_ICar.Show()}上班");
        }
    }
        static void Main(string[] args)
        {        
              ICar car = new BMW();
              ChinesePeopleInterface people = new ChinesePeopleInterface();
              people.SetDependent(car);
              people.Run();
              Console.Read();    
        }      
View Code

分析,介面依賴是定義一個設置依賴的方法,然後被依賴類繼承並實現這個介面

六、IOC容器

IOC容器是一個DI框架,主要功能有一下幾點

1.動態創建、註入依賴對象;

2.管理對象生命周期

2.映射依賴關係

常見的IOC容器:Spring.NET,Castle Windsor, Ninject,Autofac,Unity等等。。。

ioc容器提供了很多豐富的API,由於時間和篇幅等關係,我會在下篇博客中和您一起學習IOC容器之一Unity,敬請期待,未完待續。。。

 

不努力一把,坐井觀天,將永遠不知道自己和別人的差距有多大,身為菜鳥的我相信,天道酬勤,大道至簡,最好的成功之道便是堅持、學習、總結。

本文版權歸作者和博客園共有,歡迎轉載,轉載請註明出處。感謝您的閱讀。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1、輸入輸出,重定向,管道 2、<(cmd);>(cmd) 3、>;<;>>;<<;>>>;<<< 4、文本處理_1:cat;head;tail;cut;wc;sort;uniq;tr;tac;rev 一、輸入輸出,重定向,管道 1、Linux 程式有三個標準的輸入輸出,分別是: 標準輸入,用數字0 ...
  • 因為一些莫名其妙的原因重寫了三遍,燒壞了兩塊STC,十分心累 ...
  • " 1、關機命令(shutdown) " " 2、管理 Windows 服務(sc) " " 3、管理任務進程(tasklist、taskkill) " " 4、顯示 TCP/IP 配置值(ipconfig) " " 5、網路診斷工具(ping) " " 6、路由跟蹤工具(tracert) " " ...
  • KGTP 介紹 KGTP 是一個能在產品系統上實時分析 Linux 內核和應用程式(包括 Android)問題的全面動態跟蹤器。 使用 KGTP 不需要 在 Linux 內核上打 PATCH 或者重新編譯,只要編譯 KGTP 模塊並insmod 就可以。 其讓 Linux 內核提供一個遠程 GDB ...
  • 翻譯了grub2官方手冊的絕大部分內容,然後自己整理了一下。因為內容有點雜,所以章節安排上可能不是太合理,敬請諒解。 本文目錄: 1.1 基礎內容 1.2 安裝grub2 1.3 grub2配置文件 1.4 命令行和菜單項中的命令 1.5 幾個常見的內置變數 1.6 grub配置和安裝示例 1.7 ...
  • 終於可以愉快的用谷歌了,容我哭一會,下麵會闡述下樓主的心塞歷程。 linux系統裡面不能翻牆,簡直就是受罪。 準備工作: 1 一個virtualbox管理器,這個是免費,挺適合新手用,還有一個是VMware,功能更加強大,不過是收費軟體 。這兩個選一個都行。 2 安裝好Ubuntu16.04,下載包 ...
  • #聲明腳本 #!/bin/bash #列印" cfb "echo " cfb " #java環境變數JAVA_HOME=/usr/java/jdk1.8.0_11CLASSPATH=$JAVA_HOME/bin #指定需要執行jar包的位置,可自行設置 JARPATH=/home/haha/Desk ...
  • " 1、文件夾操作 " "1.1、DIR(directory)命令" "1.2、TREE 命令" "1.3、CD(change directory)命令" "1.4、MD(make directory)命令" "1.5、RD(remove directory)命令" " 2、文件操作 " "2.1、 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...