Net 相依性注入 學習筆記 1.0

29
1 讀讀讀讀 : Sean Chen 2014/07/22
  • Upload

    -
  • Category

    Software

  • view

    463
  • download

    12

description

.Net Dependency Injection

Transcript of Net 相依性注入 學習筆記 1.0

Page 1: Net 相依性注入 學習筆記 1.0

1

讀書心得 : Sean Chen

2014/07/22

Page 2: Net 相依性注入 學習筆記 1.0

2

Page 3: Net 相依性注入 學習筆記 1.0

3

實作物件

• 壓縮元件 (Zip, 7Zip, Rar)• ZipCompressor obj = new ZipCompressor();• 7ZipCompressor obj = new 7ZipCompressor();• RarCompressor obj = new RarCompressor();

Page 4: Net 相依性注入 學習筆記 1.0

4

Outline

• 啥是相依性注入 (Dependency Injection; DI), 為啥要他 ?• DI 的 Hello Word! 等級範例• DI 的三種注入方式• 不得不談設計模式• 過度注入的陷阱和迷思• DI 容器• Unity 範例實作… 希望我有時間能力看到這章

Page 5: Net 相依性注入 學習筆記 1.0

5

為啥需要 DI

• 舉個例子• ZipCompressor obj = new ZipCompressor();• RarCompressor obj = new RarCompressor();

<appSettings>    <add key="CompressorClassName" value="MyLib.ZipCompressor, MyLib" /> <appSettings>

var className = ConfigurationManager.AppSettings["CompressorClassName"];             Type aType = Type.GetType(className);             ICompressor obj = (ICompressor)System.Activator.CreateInstance(aType);

壓縮元件1. Zip2. 7zip3. Rar

"MyLib.RarCompressor, MyLib"

Page 6: Net 相依性注入 學習筆記 1.0

6

DI 的好處•提高可維護性

•建立寬鬆耦合

•增加可測試性

•相容於平行開發• 針對介面寫程式( program to an interface )。

Page 7: Net 相依性注入 學習筆記 1.0

7

所以倒底啥是 DI

•How to explain dependency injection to a 5-year old?• 當你自己去開冰箱拿東西時,很可能會闖禍。你可能忘了關冰箱

門、可能會拿了爸媽不想讓你碰的東西,甚至冰箱裡根本沒有你想要找的食物,又或者它們早已過了保存期限。• 你應該把自己需要的東西說出來就好,例如:「我想要一些

可以搭配午餐的飲料。」然後,當你坐下用餐時,我們會準備好這些東西。

Via: http://stackoverflow.com/questions/1638919/how-to-explain-dependency-injection-to-a-5-year-old

Page 8: Net 相依性注入 學習筆記 1.0

8

所以倒底啥是 DI

• DI 就是一種 設計原則 與 模式「針對介面寫程式, 而非針對類別實作」

• DI VS. IoC ( 控制反轉 )

Page 9: Net 相依性注入 學習筆記 1.0

9

範例 : 雙因素驗證 (two-factor authentication)

• 需求說明 :• 1. 檢查帳號密碼• 2. 發送一組隨機驗證碼• 3. 使用者輸入驗證碼• 4. 驗證碼確認無誤,讓使用者登入系統。

• 讓我們來看看 Code…C:\Users\Sean\OneDrive\ 文件 \vs2013\Projects\DI_Ch1_AuthenticationService_NotUseDI

Page 10: Net 相依性注入 學習筆記 1.0

10

• MainApp 類別使用 AuthenticationService 提供的驗證服務• AuthenticationService 又依賴 User 和 EmailService 類別

• 如果驗證碼要從 Email 改成手機 “簡訊” 發送呢 ?

Page 11: Net 相依性注入 學習筆記 1.0

11

範例 : 雙因素驗證 (two-factor authentication)• 修改原本的程式碼

改成支援 ShortMessage ( 簡訊 ) 方式發送驗證碼

• 讓我們來改改 Code…C:\Users\Sean\OneDrive\ 文件 \vs2013\Projects\DI_Ch1_AuthenticationService_NotUseDI

• 違反 開放/封閉原則 (Open/Close Principle ; OCP)

Page 12: Net 相依性注入 學習筆記 1.0

12

開放/封閉原則 (Open/Close Principle ;OCP)• 對開放擴充 , 對修改封閉軟體程式的單元,應該要夠開放,以便擴充功能,同時要夠封閉,以避免修改既有的程式碼。• S.O.L.I.D (物件導向設計原則之一 )• SRP (Single Responsibility Principle): 單一職責原則• OCP (Open/Closed Principle): 開放 /封閉原則• LSP (Liskov Substitution Principle): 里氏替換原則• ISP (Interface Segregation Principle): 介面隔離原則• DIP (Dependency Inversion Principle): 相依反轉原則

Page 13: Net 相依性注入 學習筆記 1.0

13

範例 : 雙因素驗證 use DI

• 讓我們來看看 Code…C:\Users\Sean\OneDrive\ 文件 \vs2013\Projects\DI_Ch1_AuthenticationService_UseDI

• 提煉介面 (Extract Interface)• 使用 DI, 讓發送驗證碼可以依賴介面 , 藉此選擇不同的發送方式

• 控制反轉 (IoC)• 物件改由外界透過 AuthenticationService 的建構函式傳進來• 相依性被移出去了 , 控制反轉啦 !!!

• DIP (Dependency Inversion Principle): 相依反轉原則• 高階模組不應依賴低階模組;他們都應該依賴抽象層( abstractions )。• 抽象層不應依賴實作細節;實作細節應該依賴抽象層。

Page 14: Net 相依性注入 學習筆記 1.0

14

注入方式• 建構式注入 (Constructor Injection)• 屬性注入 (Property Injection)• 方法注入 (Method Injection)

Page 15: Net 相依性注入 學習筆記 1.0

15

屬性注入 (Property Injection)

• 又名 “設定函式注入”• 與建構式注入的區別• 『屬性注入』時機比『建構式注入』來的晚• 外界不一定會設定該屬性

• 讓我們來看看 Code…C:\Users\Sean\OneDrive\ 文件 \vs2013\Projects\DI_Ch2_AuthenticationService_PropertyDI

Page 16: Net 相依性注入 學習筆記 1.0

16

方法注入 (Method Injection)

•適用時機• 提供服務的類別不需要在整個類別中使用特定相依物件,

而只有在用戶端呼叫某些方法時才需要傳入那些物件。

• 用戶端每次呼叫特定方法時可能會傳入不同的物件,而這些物件唯一相同之處是它們都實作了同一個介面(或繼承自同一個抽象類別)。

• 讓我們來看看 Code…C:\Users\Sean\OneDrive\ 文件 \vs2013\Projects\DI_Ch2_AuthenticationService_MethodDI

Page 17: Net 相依性注入 學習筆記 1.0

17

使用 DI 的時機• DI 並非萬能也非一定使用就比較好 , 一切還是要看情境 !•主要可以應用在第三方套件 , 可能會經常更換變動的類 !

• 不建議使用 DI 的情境• 小型專案 , 需求單純• 大型專案到處都是 DI, 會讓後續接手的新進成員較難追到實作物件的類

別到底是哪個 , 僅能依靠 逐步偵錯一步步追 .• 老代碼設計沒有考慮寬鬆耦合 , 引入 DI 將會困難重重 ( 不如打掉重練 ?)

Page 18: Net 相依性注入 學習筆記 1.0

18

窮人的 DI

• 和特定 DI 工具 (Autofac, Unity… ) 無關•運用 DI 技術通常也需要搭配一些設計模式 (Design Patterns)• Factory Method, Decorator, Composite, Adapter• Ambient Context 模式• Service Locator 模式

Page 19: Net 相依性注入 學習筆記 1.0

19

不得不談設計模式• Null Object 模式• Decorator 模式 (UPS 不斷電系統 )• Composite 模式 (延長線 )• Adapter 模式 (變壓器 )• Factory 模式 (工廠能夠生產特定類型的物件 )• FactoryMethod (工廠方法 )• Simple Factory ( 簡單工廠 )• Abstract Factory ( 抽象工廠 )

Page 20: Net 相依性注入 學習筆記 1.0

20

過度注入的陷阱和迷思•半吊子注入

• 過度注入

Page 21: Net 相依性注入 學習筆記 1.0

21

過度注入的陷阱和迷思 -半吊子注入• 「過家門而不用」,轉手又交給下一層• A 不想和 C1, C2 耦合 , 卻直接 new B() class A

{ private readonly B objB; public A(C1 c1, C2 c2) { // 建立 B 物件時,將外界注入的 c1 和 c2 再注入至 B 的建構函式。 this.objB = new B(c1, c2); } public void ExecuteTask() { objB.ExecuteTask(); }}

Page 22: Net 相依性注入 學習筆記 1.0

22

過度注入的陷阱和迷思 -半吊子注入•阻止相依蔓延• 若類別 A 不需要動態切換• 則類別 A 阻止蔓延• 形成黑箱• 且可達到封裝性

• 組合根 (Composition Root)

class A{ private readonly B objB; public A() { var c1 = new C1(); var c2 = new C2(); this.objB = new B(c1, c2); }}

Page 23: Net 相依性注入 學習筆記 1.0

23

過度注入的陷阱和迷思 -半吊子注入•阻止相依蔓延

• 組合根 (Composition Root)• 修改類別 A 的建構函式• 使其改為注入 B 物件

class A{ private readonly B objB; public A(B b) { this.objB = b; } public void ExecuteTask() { objB.ExecuteTask(); }}

Page 24: Net 相依性注入 學習筆記 1.0

24

過度注入的陷阱和迷思 -半吊子注入•阻止相依蔓延

• 組合根 (Composition Root)• 修改類別 A 的建構函式• 使其改為注入 B 物件

class Program{ public static void Main() { // 在這裡把所有需要的物件一次組合好 var c1 = new C1(); var c2 = new C2(); var b = new B(c1, c2); var a = new A(b); a.ExecuteTask(); }}

Page 25: Net 相依性注入 學習筆記 1.0

25

過度注入的陷阱和迷思 - 過度注入• 改用「屬性注入」和「方法注入」• 使用 Factory 模式、 Ambient Context 、或 Service Locator 模式•將建構函式的多個參數重構成 Parameter Object (參數物件 )•多載建構函式 (overloaded constructors)•重構成 Facade 模式

class AuthenticationService{ public AuthenticationService (

IMessageService service,

IUserRepository userRepo,

IUser user,IValidator validator,ILogger logger)

{ // 略 }}

Page 26: Net 相依性注入 學習筆記 1.0

26

DI 容器• 他就是一套類別庫• 提供的功能

• 物件組合• 物件生命週期管理• 攔截 (interception)

• 現成的第三方 DI 容器• Autofac• Ninject• Spring.NET• StructureMap• UnityWindsor• 自製容器

Page 27: Net 相依性注入 學習筆記 1.0

27

回家作業 1

•蛋蛋的 Controller 呼叫 Service 有使用 DI 嗎 ? 那他是使用哪種 DI ?

•其實蛋蛋的 Controller 有結合 Autofac 的 DI 容器 , 那蛋蛋是怎樣使用 Autofac 的呢 ?• Autofac 的註冊類別設定大部分都會放在 Global.asax 裡面• 在 ~/App_Start 目錄下建立 AutofacConfig.cs (ResufalService.config?) 檔案• Application_Start() 方法裡再去呼叫 AutofacConfig.Bootstrapper() 方法

• Via: http://kevintsengtw.blogspot.tw/2013/09/aspnet-mvc-autofac.html#.U8tzPfmSyE8

Page 28: Net 相依性注入 學習筆記 1.0

28

回家作業 2

• 第 4 章 : DI 與 ASP.NET MVC 分層架構• 分層架構簡介

• Repository 模式 (ex. SQL Server, MySQL, Oracle)• MVC 分層架構範例 V1 -緊密耦合• MVC 分層架構範例 V2 -寬鬆耦合• MVC 分層架構範例 V3 -嘗試簡化• MVC 分層架構範例 V4 -使用 Unity

Page 29: Net 相依性注入 學習筆記 1.0

29

回家作業 3

• 使用 DI 容器• 第 7 章: Unity 參考手冊

• DI 容器的使用方式• 建立 DI 容器• 註冊型別• 解析型別