日韩久久久精品,亚洲精品久久久久久久久久久,亚洲欧美一区二区三区国产精品 ,一区二区福利

Dependency Injection 筆記 (3)

系統 1998 0

上集 接著要來進一步了解的是 DI 的實現技術,也就是注入相依對象的方式。這里介紹的依賴注入方式,又稱為「窮人的 DI」(poor man’s DI),因為這些用法都與特定 DI 工具無關,亦即不使用任何現成的 DI 框架(例如 Unity、Autofac)。畢竟,DI 只是一組設計原則與模式,不依賴任何工具也能實現。

(本文摘自電子書:《 .NET?依賴注入 》)

?

設計模式梗概

每個模式都描述了一個不斷發生在我們周遭的問題,然后描述該問題的核心解法,于是你便可以一再使用該解法,而無須對同樣的事情做兩次工。
—— Christopher Alexander. A Pattern Language.

除了第 1 章提到的 S.O.L.I.D. 設計原則,在運用 DI 技術時,也經常需要搭配一些設計模式(design patterns),例如 Factory Method(工廠方法)、Decorator(裝飾)、Composite(組合)、Adapter(轉換器)等等。基于后續章節討論的必要,本節將介紹幾個相關的設計模式。如需比較完整深入的介紹,可參考相關書籍,例如:《面向對象設計模式》、《深入淺出設計模式》、《重構-向范式前進》等等。


小引-電器與接口

日常生活中,四處可見電器用品,例如電視、微波爐、計算機等等。這些電器通常都有條電線,電線尾端是個插頭,而當我們要使用這些電器時,就把插頭插在墻壁或電源插座上,電器便能夠獲得所需之電力。一般情況下,沒有人會舍插座不用,而把電器的電源線固定焊在墻壁的電源插座。假使真這么做,萬一有一天電視或計算機故障而需要維修,那可就麻煩了。

Dependency Injection 筆記 (3)

不只電源插座,計算機的 USB 插槽也一樣——它們都具備寬松耦合的特性。這里的電源插座或 USB 插槽,對應到軟件世界里的概念,便是接口。一個接口就等于是一份規格,而各家廠商所生產的各式各樣的電源插座或 USB 插槽,就是遵照其標準規格(接口)所實現出來的產品,或簡稱實現品。用軟件的術語來說,這些實現品就是類型——實現了特定接口的類型。

接口的威力即在于一旦訂出標準規格,各家廠商便可依照標準接口來制作各類產品。對使用者來說,好處則是享有多種選擇,因為他們不會被特定廠商的產品綁住;只要他們高興,隨時可以更換不同的產品,而且通常是即插即用。在軟件的世界里,接口也有同樣的好處:讓類型與類型之間保持寬松耦合,以便提供隨時抽換實現類型的彈性。


Null Object 模式

回到電源插座的例子。如果我們將計算機的電源線從插座上拔起,它們就只是彼此不再連接而已,計算機和插座并不會因此而著火或爆炸。但是在軟件程序的世界里,若對象 A 會調用對象 B(對象 A 依賴對象 B),而當你將對象 B 移除,亦即對象 B 不存在時,程序就會發生 NullReferenceException 類型的錯誤。于是,我們常常會在程序里面加入檢查對象參考是否為 null 的邏輯,例如:

      
        if
      
       (anObject != 
      
        null
      
      
        )

    anObject.DoSomething();


      
      
        else
      
      
        

    DoSomethingElse();
      
    

如果在程序中一再重復寫這些檢查 null 的邏輯,代碼便會膨脹,而且在解讀程序的主要邏輯時,常常得要跳過這些檢查邏輯,多少會形成閱讀代碼的阻礙。針對此問題,我們可以設計一個空的、完全不做任何事的類型,然后在變量有可能是 null 的地方,讓它們指向那個空的對象。這種模式叫做 Null Object。

Null Object 的優點:可減少編寫判斷對象參考是否為 null 的防錯邏輯。但前提是開發人員得知道有 Null Object 可用,否則還是會寫出多余的防錯代碼。

Null Object 類型通常要實現某個接口(或繼承自抽象類型),但實現代碼完全沒做任何事,即所有方法都只是個空殼子,或僅提供無害的默認行為。以程序中常用的 logging(日志)機制為例,我們可以將寫入日志的操作定義成一個 ILogger 接口,然后依實際需要實現不同的 logging 類型,例如用來將日志訊息輸出至 Console 的 ConsoleLogger。此外,考慮到應用程序有時候可能不需要紀錄任何訊息,我們可以實現一個 NullLogger 類型,當作 Null Object 使用。結構圖如下。

Dependency Injection 筆記 (3)


底下分別是 ILoger 接口以及 NullLogger 和 ConsoleLogger 類型的代碼:

      
        public
      
      
        interface
      
      
         ILogger

{

    Log(
      
      
        string
      
      
         msg);

}




      
      
        public
      
      
        class
      
      
         NullLogger : ILogger

{

    
      
      
        public
      
      
        void
      
       Log(
      
        string
      
      
         msg)

    {

        
      
      
        //
      
      
         不做任何事
      
      
            }

}




      
      
        public
      
      
        class
      
      
         ConsoleLogger : ILogger

{

    
      
      
        public
      
      
        void
      
       Log(
      
        string
      
      
         msg)

    {

        Console.WriteLine(msg);

    }

}
      
    

?

像底下這個函式,調用端只要傳入 ConsoleLogger 對象,日志訊息就會輸出至 Console;而當調用端想要停止記錄日志,便可傳入 NullLogger 對象。如此一來,就不用在每次寫入日志訊息時都重復寫一遍檢查 logger 對象是否為 null 的防錯邏輯。

      
        void
      
      
         DoSomething(ILogger logger)

{



    logger.Log(
      
      
        "開始執行
      
      
         DoSomething 函式。
      
      
        "
      
      
        );

    ....

}
      
    

?

Note: ?Null Object 本身并不需要「進化」成真正有做事的對象,因為它的存在就是為了提供一個完全不做任何事、不具任何意義的對象。
?

Decorator 模式

一般情況下,如果在使用計算機時突然停電了,尚未儲存的數據就會消失不見。為了解決此問題,我們可以在墻壁的電源插座與計算機電源線之間加入一個不斷電系統(UPS)。此時,UPS 的電源線會接在墻壁的電源插座上,而計算機的電源則改接在 UPS 上。此三者在串接的時候,都是通過單一的標準接口:插座。類似這種通過同一接口來串接多個不同對象的作法,叫做Decorator Pattern(裝飾模式)。此模式可以讓我們為對象層層迭加新的功能上去,而無須修改現有的類型。下圖為 Decorator 模式 的結構圖。
?
Dependency Injection 筆記 (3)
?

延續前面的 logging 范例,假設想要在每次輸出 log 訊息時額外加上當時的日期時間,而且前提是不可修改現有的 ILogger 和 ConsoleLogger 類型,該怎么做?

我們可以使用 Decorator 模式。作法為:設計一個新的類型,此類型不僅要實現 ILogger 接口,而且還需要使用現有的 ConsoleLogger 對象來輸出 log 訊息。簡單起見,我就把這個類型命名為 DecoratedLogger。代碼如下:

?
          
            public
          
          
            class
          
          
             DecoratedLogger : ILogger

{

    
          
          
            private
          
          
             ILogger logger;

 

    
          
          
            public
          
          
             DecoratedLogger(ILogger aLogger)

    {

        logger 
          
          =
          
             aLogger;

    }

 

    
          
          
            public
          
          
            void
          
           Log(
          
            string
          
          
             msg)

    {

        logger.Log(DateTime.Now.ToString() 
          
          + 
          
            "
          
          
             - 
          
          
            "
          
           +
          
             msg);

    }

}
          
        

?

下圖描繪了這個簡略版本的 Decorator 模式范例的類型結構:
?
Dependency Injection 筆記 (3)
?
于是,在客戶端程序中使用這個新的 DecoratedLogger 來輸出 log 訊息時,可以這么寫:
?
          
            void
          
          
             DoSomething()

    {

        ILogger logger 
          
          = 
          
            new
          
           DecoratedLogger(
          
            new
          
          
             ConsoleLogger());

        logger.Log(
          
          
            "
          
          
            Hello, 裝飾模式!
          
          
            "
          
          
            );

    }
          
        

?

你可以看到,在這次的修改當中,現有的 ILogger 和 ConsoleLogger 完全沒有動到。我們只增加了一個新類型(DecoratedLogger),就為應用程序加上了新功能。這也就符合了第 1 章提過的 OCP(開放/封閉原則)。
?
(摘自:《 .NET?依賴注入 》)
?

Dependency Injection 筆記 (3)


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 曲阳县| 静海县| 威宁| 根河市| 辽宁省| 象山县| 南开区| 大丰市| 安泽县| 六安市| 泊头市| 扎兰屯市| 三都| 商南县| 赣州市| 福安市| 铜山县| 嘉义县| 南平市| 民乐县| 枣庄市| 合水县| 含山县| 洛扎县| 栾城县| 军事| 闽侯县| 石嘴山市| 新沂市| 钦州市| 宜宾县| 阆中市| 峨眉山市| 竹山县| 德昌县| 武宣县| 威海市| 洪湖市| 黔东| 桂平市| 杭州市|