傻嘎,IOC原來是這樣子的


昨天有網友Call我留言,說他寫了個DI架構,讓我有時間看看,於是我就上去看了:

文章地址: http://www.cnblogs.com/lenic/archive/2013/06/04/3117893.html

發現是E文的,於是回復:

路過秋天  22: 32: 43 
怎么還寫E文的
NOoK  22: 33: 03 
直接在 CodePlex 上寫的介紹
NOoK  22: 33: 08 
然后就粘過來了
NOoK  22: 33: 15 
結果還被博客園下架了。。。
NOoK  22: 34: 40 
悲催的
路過秋天  22: 35: 34 
誰讓你 Look it on CodePlex
NOoK  22: 35: 41 
。。。 

我錯了 

 

接着他讓我下載他的處女開源項目,讓我看看:

NOoK  22 : 36 : 09  
明天再修改一下吧
路過秋天  22: 37: 26 
平時都習慣寫英文?
NOoK  22: 37: 40 
肯定不是啊
NOoK  22: 38: 03 
在 CodePlex 上面寫了,懶得改就貼過來了
路過秋天  22: 38: 43 
平時也在CodePlex上面寫?
NOoK  22: 38: 54 
第一個開源項目。。。
NOoK  22: 40: 35 
改好了再說吧
路過秋天  22: 40: 46 
 
NOoK  22: 41: 14 
你可以下載代碼看看,維護了好幾年了
路過秋天  22: 43: 17 
Ok,我看看
路過秋天  22: 48: 23 
掃了一下,不是很理解
NOoK  22: 50: 15 
思路是,注冊委托進字典,需要的時候,再用委托生成對象
NOoK  22: 50: 41 
然后衍生了多個生存周期;
路過秋天  22: 50: 50 
實用場景 ?
NOoK  22: 51: 42 
一樣啊
NOoK  22: 51: 56 
就是IOC的使用場景
NOoK  22: 52: 46 
這個核心代碼,類似於Ninject,沒配置 


由於本人對IOC,雖然曾多次看過網上的文章介紹,除了“依賴注入,控制反轉”這八個字,沒有多余的存檔記憶了。

后來的聊天,我讓他給我舉一個實用場景,畢竟我是實戰派的,一種模式或一種東東,只有擺在現實的場景,並且有過深刻的使用痕跡,才能記的深,用的勞。

像那些設計模式的文章,一來就是UML圖,舉個例子基本就是貓和狗,要不就是會飛的鴨子。
費我十八層腦力,終於理解明白了。
第二天一睡醒,基本沒印象。
再過些天。。。連設計模式的名字都不知叫什么了。


后來中間擰了一陣,基本沒擰在一塊,我要的是實戰場景,他老給我講理論。

於是我就遷就他學理論了,我搜索看了看IOC的的基本介紹:

控制反轉(Inversion of Control,英文縮寫為IoC)是一個重要的面向對象編程的法則來削減計算機程序的耦合問題。 控制反轉還有一個名字叫做依賴注入(Dependency Injection)。簡稱DI。

早在2004年,Martin Fowler就提出了“哪些方面的控制被反轉了?”這個問題。他總結出是依賴對象的獲得被反轉了。基於這個結論,他為控制反轉創造了一個更好的名字:依賴注入。許多非凡的應用(比HelloWorld.java更加優美,更加復雜)都是由兩個或是更多的類通過彼此的合作來實現業務邏輯,這使得每個對象都需要,與其合作的對象(也就是它所依賴的對象)的引用。如果這個獲取過程要靠自身實現,那么如你所見,這將導致代碼高度耦合並且難以測試。
IoC 亦稱為 “依賴倒置原理”( " Dependency Inversion Principle ")。差不多所有框架都使用了“倒置注入(Fowler  2004)技巧,這可說是IoC原理的一項應用。SmallTalk,C++, Java 或各種.NET 語言等面向對象程序語言的程序員已使用了這些原理。
控制反轉是Spring框架的核心。
應用控制反轉,對象在被創建的時候,由一個調控系統內所有對象的外界實體,將其所依賴的對象的引用,傳遞給它。也可以說,依賴被注入到對象中。所以,控制反轉是,關於一個對象如何獲取他所依賴的對象的引用,這個責任的反轉。

oC就是IoC,不是什么技術,與GoF一樣,是一種設計模式。

 

當然了,資料還有一大堆,就不詳細貼了。

后來他為了擰過我,決定給我培訓一下,給我出了道題:

NOoK  23: 30: 52 
要不要做題?
NOoK  23: 31: 28 
一個四則運算的
路過秋天  23: 32: 06 
說說看
NOoK  23: 32: 06 
好吧,我睡覺了,晚安咯
NOoK  23: 33: 30 
通過不同的配置,加載不同的程序集,實現四則運算
NOoK  23: 34: 19 
輸入兩個參數,運算得到結果
NOoK  23: 35: 01 
不允許用反射
路過秋天  23: 35: 31 
其它條件呢?
NOoK  23: 35: 39 
沒有了
路過秋天  23: 36: 33 
使用程序集,卻不允許用反射?
NOoK  23: 36: 42 
我就是想通過兩個數字,得到結果,怎么運算我不管,只要給我結果就好
NOoK  23: 37: 07 
你可以寫到一個程序集里面
路過秋天  23: 37: 28 
過程就是修改配置?
NOoK  23: 37: 29 
我說錯了,加載程序集就是反射
NOoK  23: 37: 51 
哥,你問偏了
NOoK  23: 38: 11 
過程你寫好
NOoK  23: 38: 34 
通過配置修改
路過秋天  23: 38: 51 
OK,我try一下
NOoK  23: 39: 09 
我等你消息啊,哈哈

 

根據要求,2-3分鍾后,我就上圖了:

根據配置,加個switch,解決了,不過既然我們在說IOC,肯定是需要不斷演進。

NOoK  0: 02: 58 
如果這里的業務很負責呢
NOoK  0: 03: 04 
不是簡單的四則運算
NOoK  0: 03: 08 
你怎么辦
路過秋天  0: 03: 14 
很負責?
NOoK  0: 03: 43 
很復雜
NOoK  0: 03: 48 
手誤
路過秋天  0: 03: 50 
既然是題目,你就舉個場景,我按場景實現
NOoK  0: 04: 06 
你應該寫4個類,對不對
NOoK  0: 04: 11 
分別實現四種運算
NOoK  0: 04: 21 
比這樣寫一個類要好
NOoK  0: 04: 28 
以后擴展就可以再寫一個類

 

好吧,很復雜的話,要分類就這樣了:

 

IOC演進
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

namespace ABCD
{
     class Program
    {
         static  void Main( string[] args)
        {
             while ( true)
            {
                Console.Read();
                 int result = GetResult( 124);
                Console.WriteLine(result);
            }
        }
         static  int GetResult( int a,  int b)
        {
             switch (GetConfig())
            {
                 case  " + ":
                     return  new A().GetResult(a,b);
                 case  " - ":
                     return  new B().GetResult(a, b);
                 case  " * ":
                     return  new C().GetResult(a, b);
                 case  " / ":
                     return  new D().GetResult(a, b);
            }
             return  0;
        }
         static  string GetConfig()
        {
             string config = AppDomain.CurrentDomain.BaseDirectory +  " config.ini ";
             return File.ReadAllText(config);
        }
    }
     public  class A
    {
         public  int GetResult( int a,  int b)
        {
             return a + b;
        }
    }
     public  class B
    {
         public  int GetResult( int a,  int b)
        {
             return a - b;
        }
    }
     public  class C
    {
         public  int GetResult( int a,  int b)
        {
             return a * b;
        }
    }
     public  class D
    {
         public  int GetResult( int a,  int b)
        {
             return a / b;
        }
    }

 

 

剛發過去,就來一句:可以提取一個接口嗎

改了改,代碼發過去如下:

IOC 演進2
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

namespace ABCD
{
     class Program
    {
         static  void Main( string[] args)
        {
             while ( true)
            {
                Console.Read();
                 int result = GetResult( 124);
                Console.WriteLine(result);
            }
        }
         static  int GetResult( int a,  int b)
        {
            IGetResult iResult =  null;
             switch (GetConfig())
            {
                 case  " + ":
                    iResult =  new A();
                     break;
                 case  " - ":
                    iResult =  new B();
                     break;
                 case  " * ":
                    iResult =  new C();
                     break;
                 case  " / ":
                    iResult =  new D();
                     break;
            }
             return iResult.GetResult(a, b);
        }
         static  string GetConfig()
        {
             string config = AppDomain.CurrentDomain.BaseDirectory +  " config.ini ";
             return File.ReadAllText(config);
        }
    }
     public  interface IGetResult
    {
         int GetResult( int a,  int b);
    }
     public  class A : IGetResult
    {
         public  int GetResult( int a,  int b)
        {
             return a + b;
        }
    }
     public  class B : IGetResult
    {
         public  int GetResult( int a,  int b)
        {
             return a - b;
        }
    }
     public  class C : IGetResult
    {
         public  int GetResult( int a,  int b)
        {
             return a * b;
        }
    }
     public  class D : IGetResult
    {
         public  int GetResult( int a,  int b)
        {
             return a / b;
        }
    }


四則變五則:

NOoK  0: 11: 51 
我現在要加一個業務
NOoK  0: 12: 00 
邏輯是 (a + b) * a
NOoK  0: 12: 07 
怎么辦 

 

只是加一個類和修改switch,代碼過去如下:

IOC 演進3
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

namespace ABCD
{
     class Program
    {
         static  void Main( string[] args)
        {
             while ( true)
            {
                Console.Read();
                 int result = GetResult( 124);
                Console.WriteLine(result);
            }
        }
         static  int GetResult( int a,  int b)
        {
            IGetResult iResult =  null;
             switch (GetConfig())
            {
                 case  " + ":
                    iResult =  new A();
                     break;
                 case  " - ":
                    iResult =  new B();
                     break;
                 case  " * ":
                    iResult =  new C();
                     break;
                 case  " / ":
                    iResult =  new D();
                     break;
                 case  " +* ":
                    iResult =  new E();
                     break;
            }
             return iResult.GetResult(a, b);
        }
         static  string GetConfig()
        {
             string config = AppDomain.CurrentDomain.BaseDirectory +  " config.ini ";
             return File.ReadAllText(config);
        }
    }
     public  interface IGetResult
    {
         int GetResult( int a,  int b);
    }
     public  class A : IGetResult
    {
         public  int GetResult( int a,  int b)
        {
             return a + b;
        }
    }
     public  class B : IGetResult
    {
         public  int GetResult( int a,  int b)
        {
             return a - b;
        }
    }
     public  class C : IGetResult
    {
         public  int GetResult( int a,  int b)
        {
             return a * b;
        }
    }
     public  class D : IGetResult
    {
         public  int GetResult( int a,  int b)
        {
             return a / b;
        }
    }
     public  class E : IGetResult
    {
         public  int GetResult( int a,  int b)
        {
             return (a + b) * a;
        }
    }

 

最后的需求,消滅switch

NOoK  0: 15: 31 

NOoK  0: 15: 37 
這里能寫一個字典嗎
NOoK  0: 15: 46 
這不就是鍵值對嗎


OK,我給出了最終代碼:

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

namespace ABCD
{
     class Program
    {
         static  void Main( string[] args)
        {
             while ( true)
            {
                Console.Read();
                 int result = GetResult( 124);
                Console.WriteLine(result);
            }
        }
         static  int GetResult( int a,  int b)
        {
            IGetResult iResult =  null;
             string key = GetConfig();
            iResult = ResultRegList.ResultList[key];
             return iResult.GetResult(a, b);
        }
         static  string GetConfig()
        {
             string config = AppDomain.CurrentDomain.BaseDirectory +  " config.ini ";
             return File.ReadAllText(config);
        }
    }
     public  interface IGetResult
    {
         int GetResult( int a,  int b);
    }
     public  class A : IGetResult
    {
         public  int GetResult( int a,  int b)
        {
             return a + b;
        }
    }
     public  class B : IGetResult
    {
         public  int GetResult( int a,  int b)
        {
             return a - b;
        }
    }
     public  class C : IGetResult
    {
         public  int GetResult( int a,  int b)
        {
             return a * b;
        }
    }
     public  class D : IGetResult
    {
         public  int GetResult( int a,  int b)
        {
             return a / b;
        }
    }
     public  class E : IGetResult
    {
         public  int GetResult( int a,  int b)
        {
             return (a + b) * a;
        }
    }
     public  class ResultRegList
    {
         static Dictionary< string, IGetResult> resultList =  new Dictionary< string, IGetResult>( 5);

         public  static Dictionary< string, IGetResult> ResultList
        {
             get
            {
                 if (resultList.Count ==  0)
                {
                    resultList.Add( " + "new A());
                    resultList.Add( " - "new B());
                    resultList.Add( " * "new C());
                    resultList.Add( " / "new D());
                    resultList.Add( " +* "new E());
                }
                 return resultList;
            }
        }


    }
}

 

接下來就是終結理論了:

NOoK  0: 23: 45 
這就是了
路過秋天  0: 24: 22 
這東西寫了很多,不過沒感覺ioc的存在
NOoK  0: 24: 23 
如果以后再添加邏輯,只要寫一個IGetResult接口的實現類,再配置到字典里面,就可以了
NOoK  0: 24: 34 
那個字典,其實就是ioc的雛形
NOoK  0: 24: 44 
IOC說到底,就是這樣的一個字典
NOoK  0: 25: 03 
通過一個條件,找到所需的實現類
NOoK  0: 25: 09 
然后用到邏輯上
NOoK  0: 25: 12 
就好了
NOoK  0: 25: 27 
再改進,就是用IOC替換你那個字典了
路過秋天 0:25:32 
通過一個條件,找到所需要的實現類,看似更像反射
NOoK 0:25:40 
這是反射嗎?
NOoK 0:26:09 
你看到了嗎?
路過秋天 0:26:11 
你看我的代碼,如果增加一個類,ResultRegList這里還需要再注冊
NOoK 0:26:18 
是的
NOoK 0:26:37 
字典是需要你手工改代碼的
路過秋天 0:26:38 
只有變更為反射,可以解決
NOoK 0:26:49 
IOC就是配置一下就可以了
NOoK 0:26:54 
不需要改代碼了
NOoK 0:27:33 
每種IOC都不一樣,最簡單的就是你寫的這種字典
NOoK 0:27:38 
然后加上反射
NOoK 0:27:42 
這容易理解
NOoK 0:27:55 
但是能用到生產上的IOC容器
NOoK 0:28:03 
都做了很多工作的
路過秋天 0:28:15 
什么工作呢?
NOoK 0:28:29 
比如你可以集成AOP
NOoK 0:28:47 
添加一些創建前、創建后的事件


大體上話就擰到這了,后面也沒多擰幾句,到了洗洗睡了的時間。

 

再回頭看這段話,理解了,IOC原來是這樣子的:

可以把IoC模式看做是工廠模式的升華,可以把IoC看作是一個大工廠,只不過這個大工廠里要生成的對象都是在XML文件中給出定義的,然后利用Java 的“反射”編程,根據XML中給出的類名生成相應的對象。從實現來看,IoC是把以前在工廠方法里寫死的對象生成代碼,改變為由XML文件來定義,也就是把工廠和對象生成這兩者獨立分隔開來,目的就是提高靈活性和可維護性。


接下來理解“依賴注入、控制反轉”八個字:

 

依賴注入:

 

首先Program里的switch本來是調用new A()這個對象,經過演進后,變成調用IGetResult接口了。
所以Program本來是依賴new A()對象,結果被IGetResult接口給插了菊花。
最終就是Program只調用IGetResult接口,Programe和new A()沒有直接依賴關系。
這就是依賴注入的解釋了。

 

 

控制反轉:

 

正常說的, new A()對象,是由Program寫死在代碼里的了,相當於控制權是在Program里。
代碼演進之后,對象的產生的控制權轉移到配置文件里。
這就是控制(權)反轉的解釋了。

 

 

文章有點長,不知道你理解了沒。


免責聲明!

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



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