日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

IOC前世今生

發布時間:2024/1/8 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 IOC前世今生 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前些天,參與了公司內部小組的一次技術交流,主要是針對《IOC與AOP》,本著學而時習之的態度及積極分享的精神,我就結合一個小故事來初淺地剖析一下我眼中的“IOC前世今生”,以方便初學者能更直觀的來學習與理解IOC!也作拋磚引玉之用。

(雖說故事中的需求有點小,但看客可在腦海中盡量把他放大,想象成一個很大的應用系統)

一、IOC雛形

1、程序V1.0

??? 話說,多年以前UT公司提出一個需求,要提供一個系統,其中有個功能可以在新春佳節之際給公司員工發送一封郵件。郵件中給大家以新春祝福,并告知發放一定數額的過節費。

???? 經分析,決定由張三、李四和王五來負責此系統的開發。

??? 其中:由張三負責業邏輯控制模塊 LogicController的開發,此處簡化為UT.LogicController.exe ;由李四負責祝福消息管理類(GreetMessageService),并集成到組件 UT.MessageService.dll中;由王五負責郵件功能幫助類(EmailHelper),并提供組件 UT.Email.dll。

???? 類依賴關系如下:

??? 王五郵件功能模塊核心代碼如下:?

public class EmailHelper {public void Send(string message){Console.Write("Frome email: " + message); } }

? 李四消息管理模塊核心代碼如下:

public class GreetMessageService {EmailHelper greetTool;public GreetMessageService(){greetTool = new EmailHelper();}public void Greet(string message){greetTool.Send(message);} }

  ??張三業務集成模塊核心代碼如下:

string message = "新年快樂!過節費5000."; MessageService.GreetMessageService service = new MessageService.GreetMessageService(); service.Greet(message);

 ?三人經過一個月的艱苦奮戰,終于大功告成,系統也在春節其間成功發出問候信。企業如此關懷,給員工帶來無比的溫暖,因此深受全體員工好評!

???? 春節過后,相應的功能也移植到了與“UT公司”相關的“UT編輯部”和“UT房產”類似的應用當中,并在后繼的“元宵”、“端午”、“中秋”等節日中得以廣泛應用。

2、程序V2.0

??? 又是一個年關將至……

??? 說真的,過節費的多少,有時可能直接影響整個假日的行程安排、從而影響假日的整體質量,因此部門領導高度重視。而郵件通知的方式,在邊遠山區常常因為受網絡環境的影響而無法正常收取,許多在外過年的同事對此頗有微詞。后經多方考證,決得采用當下非常主流的電話語言播報的方式進行通知。

??? 于是乎,張三、李四、王五又忙起來了。但李四,卻有點頭疼了,因為他的模塊現在不僅在“UT公司”內部使用,而且還在“UT編輯部”和“UT房產”也都有獨立運行。如何讓此處變化影響最小,就得費點腦筋。為了達到較好的效果,李四決定按以下方式進行整改。

??? ①、初始設計方案如下:

??? 首先為了能讓不同“祝福方式”能有效替換,決定以“面向接口”的方式來進行分離。同時,讓EmailHelper的郵件通知類和TelephoneHelper的語音播報類都實現此接口。核心代碼如下:

public interface ISendable {void Send(string message); }public class EmailHelper : ISendable {public void Send(string message){Console.Write("Frome email: " + message);} }public class TelephoneHelper : ISendable {public void Send(string message){Console.Write("Frome telephone: " + message);} }

  ?再者,為了方便兼容新舊產品,要求Controller決定當前采用什么方式進行通信,并以參數方式傳給消息管理模塊,核心代碼如下:

public enum SendToolType {Email,Telephone, }

  【備注】:上述代碼,并不是一個優秀的設計,在后繼的優化方案當中將被去除。

public class GreetMessageService {ISendable greetTool;public GreetMessageService(SendToolType sendToolType){if (sendToolType == SendToolType.Email){greetTool = new UT.EmailV20.EmailHelper();}else if (sendToolType == SendToolType.Telephone){greetTool = new UT.TelephoneV20.TelephoneHelper();}}public void Greet(string message){greetTool.Send(message);} }

  ?最后,業務集成模塊結合具體業務需求進行適當的調整,核心代碼如下:?

?

string message = "新年快樂!過節費5000."; GreetMessageService service = new GreetMessageService(SendTool.Telephone); service.Greet(message);

???? 眼看即將完工,但李四卻越看越不順眼,因為考慮到以后可能再添加新的祝福方式,這種未來的不確定性,一定會讓李四現有的枚舉SendToolType和 GreetMessageService中的構造函數不斷的進行更改,這將會是一個沒完沒了工作。

???? 再說了,既然張三要傳SendToolType給我,也就是說在具體產品應用時,張三的模塊肯定是知道要采用什么方式進行祝福,那么何不讓他直接把祝福方式的實例而不是簡單的方式類型給我呢?這樣,我不就省事了嗎,于是乎把設計進行了優化。

???? ②、優化后設計方案:

?

? ?

??? 又是一個月的苦戰……

??? 王五的代碼不受影響。

??? 李四刪除 SendToolType枚舉,同進把GreetMessageService改成如下:

public class GreetMessageService {ISendable greetTool;public GreetMessageService(ISendable sendtool){greetTool = sendtool;}public void Greet(string message){greetTool.Send(message);} }

  ?張三,也把業務邏輯控制部分改成如下:

string message = "新年快樂! 過節費5000."; ISendable greetTool = new TelephoneHelper(); GreetMessageService service = new GreetMessageService(greetTool); service.Greet(message);

  

最終:張三更新UT.LogicController.exe中的實現;李四更新了UT.MessageSevice.dll,王五提供新的組件:UT.Telephone.dll,并把接口集成到一個叫UT.Core.dll的庫中。經多方集成測試后系統運行良好!

????【點評】:

????李四此處成功的利用“接口分離”、并結合“依賴倒置”的方式,使得自己負責的模塊初步具備了應對新增祝福方式的擴展要求。同時由于其采用的“依賴注入”方式要求李四的業務邏輯控制模塊對其所需的?“ISendable”實例進行注入,理論上已經初步具體了“IOC反轉控制”的雛形。

??? 對“IOC反轉控制”此時帶來的優勢就是:確保了“紅色框”內的模塊是具有應對變化的能力,在后繼新增新祝福方式時,UT.MessageService.dll組件可以完全不做任何修改。

?

3、V2.1

??? 由于電話語言播報必須接聽、過后不便留底查詢等不足也常被人們詬病,因此短信通知的方式被提上議程。

??? 在此要求下,王五提供了新的組件:UT.GSN.dll。核心代碼如下:

public class SMSHelper : ISendable {public void Send(string message){Console.WriteLine("Frome SMS: " + message);} }

  

?張三也把代碼改成了如下,

string message = "新年快樂! 過節費5000."; ISendable greetTool = new SMSHelper(); GreetMessageService service = new GreetMessageService(greetTool); service.Greet(message);

??? 李四坐享其成!

?

4、V2.2

??? 祝福方式日新月異人們的要求也是不斷發展,沒過多久短信方式太呆板、信息量不足等缺陷也暴露出來,微信深受大伙青睞。

??? 在此要求下,王五提供了新的組件:UT.Wechat.dll。核心代碼如下:

public class WechatHelper : ISendable {public void Send(string message){Console.WriteLine("Frome wechat: " + message);} }

  ?張三也把代碼改成了如下:?

string message = "新年快樂! 過節費5000."; ISendable greetTool = new WechatHelper(); GreetMessageService service = new GreetMessageService(greetTool); service.Greet(message);

  

李四再次坐享其成!!

????????

二、IOC擴展

1、李四的逍遙自在與張三的焦頭爛額

??? ?由于采用了IOC反轉控制的思想,現在不管系統如何變化,李四負責的模塊總的來說還是相當穩定,因此這些年李四過的可謂逍遙自在。然而,相比之下張三卻因為產品在UT公司、UT編輯部、UT房產等都有獨立應用,且各自使用的版本又不盡相同,因此要同時維護三個版本,可謂是焦頭爛額。

??? 當然張三曾經也想統一各個版本,從而實現代碼的統一維護。為此還專門與各相關主管溝通過、協調過,然而由為UT編輯部與電信服務商早有合作所有短信免費,因此短信方式最得人心;而UT房產基于對信息接收者身份的特殊性考慮,郵件通知被認為是不二選擇。因此,張三統一版本的夢想最終還是無果而終。

???? 我們來看看此時的張三同時維護著三個系統,其中各自核心代碼基本如下:

??? UT公司(微信方式)

string message = "新年快樂! 過節費5000."; ISendable greetTool = new WechatHelper(); GreetMessageService service = new GreetMessageService(greetTool); service.Greet(message);

??? UT編輯部(短信方式)?

string message = "新年快樂! 過節費5000."; ISendable greetTool = new SMSHelper(); GreetMessageService service = new GreetMessageService(greetTool); service.Greet(message);

???? UT房產(郵件方式)

string message = "新年快樂! 過節費5000."; ISendable greetTool = new EmailHelper(); GreetMessageService service = new GreetMessageService(greetTool); service.Greet(message);

??? 這些年,本著對工作和客戶的認真負責,張三長時間在這些“版本維護”、“產品兼容”等臟活累活中摸爬滾打,現在是心力憔悴……

?

2、張三的出路

??? 某日張三與李四觥籌交錯、把酒言歡……

??? 酒過三巡,張三對李四說:當年你的模塊因“IOC反轉控制”而脫身,卻把“變化點”反轉到我模塊,由我來生成特定的對象,然后再向你注入。這樣你是輕松了,但我卻深陷泥潭……

?

??? 面對張三的吐槽,李四只能給張三進行細心分析:

??? 首先、MessageService消息管理模塊作為一個消息專用服務,其實對“是采用郵件還是微信方式進行祝福”這樣的功能性把控本身是不具主動權,由這個模塊來負責實在是有點鞭長莫及,即便強扭到一起,這瓜也鐵定甜不了。

??? 還有,本著單一職責的原則本消息服務其實是不方便過多地去處理本應該是業務邏輯處理的類似“選擇祝福方式”這種事情。理論上,作為業務集成方的“LogicController”負責處理這類業務應該是責無傍代。

??? 再者,作為新增需求,王五為此而新增組件(dll)那是必不可少;張三作為業務的總集成方也是難以脫身;由于新增需求而引起的變化,對張三和王五產生影響也是情理之中。即便退一萬步來說,就算沒有“反轉控制”張三也是要面對變化的(就像V2.0初始方案中的傳入SendToolType參數),因此有無“反轉控制”對張三而言該變的始終還是要變化。那么現在采用“IOC反轉控制”而成全了李四的穩定,對張三來說這是個“利人不損已”的買賣。

??? 最后,不管從架構設計還是開發效率上來說,“IOC反轉控制”雖說把變化點從李四的“MessageService”模塊反轉到了張三的“LogicController”模塊當中,但這符合“SOLID面向對象設計”的原則,可以說是一個好的設計,本無可厚非!

??? 聽完李四的論述,張三覺得甚是有理,酒不免醒了三分!由于兩人都是這個行業打拼多年的老鳥,爭論也是點到即止。馬上把交流的重點轉移到“如何解決張三同時維護三個產品”的尷尬處境上來。

? ? 經過深入分析,兩人覺得要脫困必須解決好如下兩個問題:

??????? ①:如何有效創建“ISendable”實例,減少由于新增祝福方式對實例創建的影響?

??????? ②:如何減少新增祝福方式而對“LogicController”模塊的沖擊,以減少維護成本?

????????

【備注】

???? SOLID面向對象的五個設計原則對于開發人員非常重要,其身影在任何大中型軟件項目中隨處可見,建議必須掌握并靈活應用。此五原則分別為:

??? 單一職責原則(Single Resposibility Principle

??? 開放封閉原則(Open Closed principle

??? 里氏替換原則(Liskov Substitution Principle

??? 接口分離原則(Interface Segregation Principle

??? 依賴倒置原則?(Dependency Inversion Principle

?????????

3、解決方案

?? 為了實現“如何有效創建ISendable實例”的問題,張三引入了“工廠模式”,由于不同的祝福方式而產生的變化,封裝在一個獨立的“SendToolFactory”類中,這樣就算以后再有變化,只要更改此類中部分代碼即可,而不影響程序中其他所有用到ISendable的地方。

????【點評】:

?????以工廠模式來實現“ISendable”對象實例的創建,是一種典型的“高內聚”與“松耦合”的設計方式,它有效的使得應用程序核心部分并不用去關心系統到底采用了什么樣的“祝福方式”,而具體的“祝福方式”則在工廠模式內部進行創建。如果以后需求有變動,那也只需在工廠做少許修改即可,程序其他代碼都將不受影響。

???? 當成功解決完第一個問題后,我們立即拉開針對“如何能實現在新增祝福方式之后,有效的控制對“LogicController”模塊的沖擊”這們問題上來。從目前程序的結構來看,在新增祝福方式之后的主要沖擊有兩方面:首先是更改工廠類中的代碼用以創建新的實例;再者是引入新的動態庫。

?????最后我們決定采用“工廠模式+反射機制”的方式來解決上述難題,并在工廠模式中依靠配置文件的節點信息,然后采用“反射機制”來動態創建相應的實例;如此一來,以后就算再有新的祝福方式采用,也只需把王五新增的動態庫拷貝過來,然后再更改一下配置文件中的節點信息就行,不再需要更改任何程序源代碼,也不再需要重新編譯生成程序。

?

4、程序V3.0

???? 采用工廠模式創建實例

public abstract class SendToolFactory{public static ISendable GetInstance(){try{Assembly assembly = Assembly.LoadFile(GetAssembly()); // 加載程序集object obj = assembly.CreateInstance(GetObjectType()); // 創建類的實例 return obj as ISendable;}catch{return null;}}static string GetAssembly(){return Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ConfigurationManager.AppSettings["AssemblyString"]); }static string GetObjectType(){return ConfigurationManager.AppSettings["TypeString"];} }

  配置文件節點信息

<?xml version="1.0" encoding="utf-8" ?> <configuration><appSettings><!--<add key="AssemblyString" value="UT.EmailV20.dll" /><add key="TypeString" value="UT.EmailV20.EmailHelper" />--><!--<add key="AssemblyString" value="UT.SMSV21.dll" /><add key="TypeString" value="UT.SMSV21.SMSHelper" />--><add key="AssemblyString" value="UT.WechatV22.dll" /><add key="TypeString" value="UT.WechatV22.WechatHelper" /></appSettings> </configuration>

  

? 自從V3.0推出后,基于“IOC反轉控制”的思想也算小有收獲,多年來產品運行良好,就算不斷有新的“祝福方式”出現,張三和李四也都不必再為之操心,同時也能適用“UT公司”、“UT編輯部”和“UT房產”等不同的場景要求,可謂皆大歡喜。

????????

點評】:

????:IOC反轉控制常見的實現手段之一就是DI依賴注入,而依賴注入的方式通常有:接口注入、Setter注入和構造函數注入。本次示例給出的代碼具備“接口注入”的特征,并通過構造函數來實現。

????:IOC反轉控制還有一種手段就是依賴查找,這種方式一般先進行類型注冊,使用時進行查找;對這種方式有興趣的朋友可以參考微軟企業庫中Microsoft.Practices.Unity.dll中的源碼(https://entlib.codeplex.com/)和詳細的示例說明整理(如:Enterprise Library 4.1 HOL)。

??? ?:依賴注入一般由調用者(LogicController)依賴IOC框架生成好實例對象,然后直接注入到被調用者(GreetMessageService)當中,被者用者內部直接使用此實例,代碼流程清晰明了;而依賴查找一般由調用者(LogicController)前期進行類型注冊,被調用者(GreetMessageService)內部依賴IOC框架獲取到想要的對象實例,然后再使用此實例。

??? ④:兩者生成實例的目的都是為了能動態創建實例,只不過創建的時機不一樣。我個人認為依賴注入分離了邏輯控制相對來說層次性更清晰明了,但在需要注入多個對象時,卻不及查找注入方式方便簡潔。

?

三、IOC框架

1、模式的復用

???????? 自從張三在上述產品開發過程中成功地總結出“IOC思想”后,在后繼的其他產品中進行了推廣與實踐。在使用的過程中,張三發現這樣的模式是可以很好的在模塊間、產品間進行有效的復用,不僅大大提高了開發效率,對產品后繼的擴展和維護都帶來不少方便。

?

2、對象容器

???????? 當然,在對“IOC思想”的實踐中,張三還發現有些地方需要完善。比如,有時我們可能要創建單一對象實例,有時卻要要創建多個對象的實例,甚至有時要創建一系列實例;有時要創建一個本地的對象實例,有時卻要創建一個遠端的服務對象實例;等等…..

為了應對復雜的對象應用,張三把原來的“對象工廠”這樣的小作坊升級成了一個功能強大的、具有一定智能水平的“IOC對象容器”,這個容器可以動態的依據參數設定或配置文件來進行有策略性的對象創建與管理,使得整個框架對對象集的管理上升到了一個更高的層次。

?

3、IOC基礎框架

???????? 張三通過前期的“接口分離”及“依賴倒置”達到了“反轉控制”的效果,并結合有效的“依賴注入”方式,實現了系統的“松耦合”架構;再通過“工廠模式 + 反射機制”有效實現了對象的動態創建,并在后期升級成“對象容器”,大大減少新增需求對程序帶來的沖擊。通過以上方式,張三成功地摸索出一套行這有效且復用性高的“IOC基礎框架”。

?

4、IOC思想

??? 后來,張三把摸索總結出的“IOC基礎框架”在公司各產品中進行了廣泛實踐,得到一致好評,并且被作為一個公共組件集成在一個叫“UT企業庫”的組件集中。從此,在張三的朋友圈中,IOC思想廣為流傳。

??? 若干年后,我們發現EJB、Spring、Struts、Asp.netMVC等框架中都能看到IOC思想的影子,這些框架都對張三最初IOC的思想作了進一步的發揚、光大。

??? 現在,IOC的思想在軟件設計與系統架構中大放異彩,然而非常遺憾中國人口中的那個神秘的張三至今也不知到底是誰。

?

四:源代碼

1、開發環境為:VS2010 + NET4.0 + Windos7

2、下載示例源代碼(IOCDemo),代碼很簡單都沒寫注釋。

轉載于:https://www.cnblogs.com/caosenianhuan/p/IOC.html

總結

以上是生活随笔為你收集整理的IOC前世今生的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。