net 相依性注入 學習筆記 1.0
DESCRIPTION
.Net Dependency InjectionTRANSCRIPT
![Page 1: Net 相依性注入 學習筆記 1.0](https://reader033.vdocuments.site/reader033/viewer/2022061202/547bb5c0b4af9fa5158b4ed5/html5/thumbnails/1.jpg)
1
讀書心得 : Sean Chen
2014/07/22
![Page 2: Net 相依性注入 學習筆記 1.0](https://reader033.vdocuments.site/reader033/viewer/2022061202/547bb5c0b4af9fa5158b4ed5/html5/thumbnails/2.jpg)
2
![Page 3: Net 相依性注入 學習筆記 1.0](https://reader033.vdocuments.site/reader033/viewer/2022061202/547bb5c0b4af9fa5158b4ed5/html5/thumbnails/3.jpg)
3
實作物件
• 壓縮元件 (Zip, 7Zip, Rar)• ZipCompressor obj = new ZipCompressor();• 7ZipCompressor obj = new 7ZipCompressor();• RarCompressor obj = new RarCompressor();
![Page 4: Net 相依性注入 學習筆記 1.0](https://reader033.vdocuments.site/reader033/viewer/2022061202/547bb5c0b4af9fa5158b4ed5/html5/thumbnails/4.jpg)
4
Outline
• 啥是相依性注入 (Dependency Injection; DI), 為啥要他 ?• DI 的 Hello Word! 等級範例• DI 的三種注入方式• 不得不談設計模式• 過度注入的陷阱和迷思• DI 容器• Unity 範例實作… 希望我有時間能力看到這章
![Page 5: Net 相依性注入 學習筆記 1.0](https://reader033.vdocuments.site/reader033/viewer/2022061202/547bb5c0b4af9fa5158b4ed5/html5/thumbnails/5.jpg)
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](https://reader033.vdocuments.site/reader033/viewer/2022061202/547bb5c0b4af9fa5158b4ed5/html5/thumbnails/6.jpg)
6
DI 的好處•提高可維護性
•建立寬鬆耦合
•增加可測試性
•相容於平行開發• 針對介面寫程式( program to an interface )。
![Page 7: Net 相依性注入 學習筆記 1.0](https://reader033.vdocuments.site/reader033/viewer/2022061202/547bb5c0b4af9fa5158b4ed5/html5/thumbnails/7.jpg)
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](https://reader033.vdocuments.site/reader033/viewer/2022061202/547bb5c0b4af9fa5158b4ed5/html5/thumbnails/8.jpg)
8
所以倒底啥是 DI
• DI 就是一種 設計原則 與 模式「針對介面寫程式, 而非針對類別實作」
• DI VS. IoC ( 控制反轉 )
![Page 9: Net 相依性注入 學習筆記 1.0](https://reader033.vdocuments.site/reader033/viewer/2022061202/547bb5c0b4af9fa5158b4ed5/html5/thumbnails/9.jpg)
9
範例 : 雙因素驗證 (two-factor authentication)
• 需求說明 :• 1. 檢查帳號密碼• 2. 發送一組隨機驗證碼• 3. 使用者輸入驗證碼• 4. 驗證碼確認無誤,讓使用者登入系統。
• 讓我們來看看 Code…C:\Users\Sean\OneDrive\ 文件 \vs2013\Projects\DI_Ch1_AuthenticationService_NotUseDI
![Page 10: Net 相依性注入 學習筆記 1.0](https://reader033.vdocuments.site/reader033/viewer/2022061202/547bb5c0b4af9fa5158b4ed5/html5/thumbnails/10.jpg)
10
• MainApp 類別使用 AuthenticationService 提供的驗證服務• AuthenticationService 又依賴 User 和 EmailService 類別
• 如果驗證碼要從 Email 改成手機 “簡訊” 發送呢 ?
![Page 11: Net 相依性注入 學習筆記 1.0](https://reader033.vdocuments.site/reader033/viewer/2022061202/547bb5c0b4af9fa5158b4ed5/html5/thumbnails/11.jpg)
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](https://reader033.vdocuments.site/reader033/viewer/2022061202/547bb5c0b4af9fa5158b4ed5/html5/thumbnails/12.jpg)
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](https://reader033.vdocuments.site/reader033/viewer/2022061202/547bb5c0b4af9fa5158b4ed5/html5/thumbnails/13.jpg)
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](https://reader033.vdocuments.site/reader033/viewer/2022061202/547bb5c0b4af9fa5158b4ed5/html5/thumbnails/14.jpg)
14
注入方式• 建構式注入 (Constructor Injection)• 屬性注入 (Property Injection)• 方法注入 (Method Injection)
![Page 15: Net 相依性注入 學習筆記 1.0](https://reader033.vdocuments.site/reader033/viewer/2022061202/547bb5c0b4af9fa5158b4ed5/html5/thumbnails/15.jpg)
15
屬性注入 (Property Injection)
• 又名 “設定函式注入”• 與建構式注入的區別• 『屬性注入』時機比『建構式注入』來的晚• 外界不一定會設定該屬性
• 讓我們來看看 Code…C:\Users\Sean\OneDrive\ 文件 \vs2013\Projects\DI_Ch2_AuthenticationService_PropertyDI
![Page 16: Net 相依性注入 學習筆記 1.0](https://reader033.vdocuments.site/reader033/viewer/2022061202/547bb5c0b4af9fa5158b4ed5/html5/thumbnails/16.jpg)
16
方法注入 (Method Injection)
•適用時機• 提供服務的類別不需要在整個類別中使用特定相依物件,
而只有在用戶端呼叫某些方法時才需要傳入那些物件。
• 用戶端每次呼叫特定方法時可能會傳入不同的物件,而這些物件唯一相同之處是它們都實作了同一個介面(或繼承自同一個抽象類別)。
• 讓我們來看看 Code…C:\Users\Sean\OneDrive\ 文件 \vs2013\Projects\DI_Ch2_AuthenticationService_MethodDI
![Page 17: Net 相依性注入 學習筆記 1.0](https://reader033.vdocuments.site/reader033/viewer/2022061202/547bb5c0b4af9fa5158b4ed5/html5/thumbnails/17.jpg)
17
使用 DI 的時機• DI 並非萬能也非一定使用就比較好 , 一切還是要看情境 !•主要可以應用在第三方套件 , 可能會經常更換變動的類 !
• 不建議使用 DI 的情境• 小型專案 , 需求單純• 大型專案到處都是 DI, 會讓後續接手的新進成員較難追到實作物件的類
別到底是哪個 , 僅能依靠 逐步偵錯一步步追 .• 老代碼設計沒有考慮寬鬆耦合 , 引入 DI 將會困難重重 ( 不如打掉重練 ?)
![Page 18: Net 相依性注入 學習筆記 1.0](https://reader033.vdocuments.site/reader033/viewer/2022061202/547bb5c0b4af9fa5158b4ed5/html5/thumbnails/18.jpg)
18
窮人的 DI
• 和特定 DI 工具 (Autofac, Unity… ) 無關•運用 DI 技術通常也需要搭配一些設計模式 (Design Patterns)• Factory Method, Decorator, Composite, Adapter• Ambient Context 模式• Service Locator 模式
![Page 19: Net 相依性注入 學習筆記 1.0](https://reader033.vdocuments.site/reader033/viewer/2022061202/547bb5c0b4af9fa5158b4ed5/html5/thumbnails/19.jpg)
19
不得不談設計模式• Null Object 模式• Decorator 模式 (UPS 不斷電系統 )• Composite 模式 (延長線 )• Adapter 模式 (變壓器 )• Factory 模式 (工廠能夠生產特定類型的物件 )• FactoryMethod (工廠方法 )• Simple Factory ( 簡單工廠 )• Abstract Factory ( 抽象工廠 )
![Page 20: Net 相依性注入 學習筆記 1.0](https://reader033.vdocuments.site/reader033/viewer/2022061202/547bb5c0b4af9fa5158b4ed5/html5/thumbnails/20.jpg)
20
過度注入的陷阱和迷思•半吊子注入
• 過度注入
![Page 21: Net 相依性注入 學習筆記 1.0](https://reader033.vdocuments.site/reader033/viewer/2022061202/547bb5c0b4af9fa5158b4ed5/html5/thumbnails/21.jpg)
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](https://reader033.vdocuments.site/reader033/viewer/2022061202/547bb5c0b4af9fa5158b4ed5/html5/thumbnails/22.jpg)
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](https://reader033.vdocuments.site/reader033/viewer/2022061202/547bb5c0b4af9fa5158b4ed5/html5/thumbnails/23.jpg)
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](https://reader033.vdocuments.site/reader033/viewer/2022061202/547bb5c0b4af9fa5158b4ed5/html5/thumbnails/24.jpg)
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](https://reader033.vdocuments.site/reader033/viewer/2022061202/547bb5c0b4af9fa5158b4ed5/html5/thumbnails/25.jpg)
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](https://reader033.vdocuments.site/reader033/viewer/2022061202/547bb5c0b4af9fa5158b4ed5/html5/thumbnails/26.jpg)
26
DI 容器• 他就是一套類別庫• 提供的功能
• 物件組合• 物件生命週期管理• 攔截 (interception)
• 現成的第三方 DI 容器• Autofac• Ninject• Spring.NET• StructureMap• UnityWindsor• 自製容器
![Page 27: Net 相依性注入 學習筆記 1.0](https://reader033.vdocuments.site/reader033/viewer/2022061202/547bb5c0b4af9fa5158b4ed5/html5/thumbnails/27.jpg)
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](https://reader033.vdocuments.site/reader033/viewer/2022061202/547bb5c0b4af9fa5158b4ed5/html5/thumbnails/28.jpg)
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](https://reader033.vdocuments.site/reader033/viewer/2022061202/547bb5c0b4af9fa5158b4ed5/html5/thumbnails/29.jpg)
29
回家作業 3
• 使用 DI 容器• 第 7 章: Unity 參考手冊
• DI 容器的使用方式• 建立 DI 容器• 註冊型別• 解析型別