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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

谈谈对IOC及DI的理解与思考

發布時間:2023/12/4 编程问答 53 豆豆
生活随笔 收集整理的這篇文章主要介紹了 谈谈对IOC及DI的理解与思考 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、前言

在實際的開發過程中,我們經常會遇到這樣的情況,在進行調試分析問題的時候,經常需要記錄日志信息,這時可以采用輸出到控制臺。

因此,我們通常會定義一個日志類,來實現輸出日志。

定義一個生成驗證的邏輯處理方法,

????public?class?Logger{public?void?AddLogger(){Console.WriteLine("日志新增成功!");}}

然后在控制臺中輸出結果。

????????static?void?Main(string[]?args){Logger?logger?=?new?Logger();logger.AddLogger();Console.Read();}

看著實現的結果,我們以為完成任務了,當其實這才是剛剛開始。

二、開始

相信大家在開發中,都會遇到這種情況,有時需要控制臺輸出,但也有可能要你輸出到文本,數據庫或者遠程服務器等等,這些都是有可能。因此最初采用直接輸出到控制臺已經不能滿足條件了,所以我們需要將上述代碼進行重寫改造,實現不同的輸出方式。

2.1 第一種方式

2.1.1 控制臺方式

用到控制臺方式輸出的時候:

????///?<summary>///?控制臺輸出///?</summary>public?class?ConsoleLogger{public?void?AddLogger(){Console.WriteLine("控制臺輸出:日志新增成功!");}}

定義一個獲取輸出日志的處理邏輯類,因此我們需要定義ConsoleLogger類并初始化

????///?<summary>///?定義一個輸出日志的統一類///?</summary>public?class?LoggerServer{private?readonly?ConsoleLogger?consoleLogger?=?new?ConsoleLogger();//添加一個私有變量的對象?個私有變量的數字對象?public?void?AddLogger(){consoleLogger.AddLogger();}}

控制臺輸出結果:

????static?void?Main(string[]?args){LoggerServer?loggerServer?=?new?LoggerServer();loggerServer.AddLogger();Console.Read();} ?

「控制臺輸出:日志新增成功!」

?

2.1.2 文本輸出

當用到文本輸出日志的時候,我們再次定義一個生成文本日志的方式

????///?<summary>///?文本輸出///?</summary>public?class?FileLogger{public?void?AddLogger(){Console.WriteLine("文本輸出:日志新增成功!");}}

然后再次定義一個獲取驗證的處理邏輯類,因此我們需要定義ImageVerification類并初始化

????///?<summary>///?定義一個輸出日志的統一類///?</summary>public?class?LoggerServer{private?readonly?FileLogger?fileLogger?=?new?FileLogger();//添加一個私有變量的對象?public?void?AddLogger(){fileLogger.AddLogger();}}

最后輸出結果:

?

「文本輸出:日志新增成功!」

?

通過以上的方式,我們實現了不同方式輸出不同日志方式,但是仔細觀察可以發現,這種方式不是一種良好的軟件設計方式。

所以可能有人會改成下面第二種方式,以接口來實現。

2.2 第二種方式

定義一個ILogger接口并聲明一個AddLogger方法

????public?interface?ILogger{void?AddLogger();}

在控制臺輸出方式中ConsoleLogger類,實現ILogger接口

????///?<summary>///?控制臺輸出///?</summary>public?class?ConsoleLogger?:?ILogger{public?void?AddLogger(){Console.WriteLine("控制臺輸出:日志新增成功!");}}

在文本輸出日志方式FileLogger類中,實現ILogger接口

????///?<summary>///?文本輸出///?</summary>public?class?FileLogger?:?ILogger{public?void?AddLogger(){Console.WriteLine("文本輸出:日志新增成功!");}}

定義一個統一的輸出日志類LoggerServer類

///?<summary> ///?定義一個獲取驗證的統一類 ///?</summary> public?class?VerificationServer {private?readonly?ConsoleLogger?consoleLogger?=?new?ConsoleLogger();//添加一個私有變量的對象?//private?readonly?FileLogger?fileLogger?=?new?FileLogger();//添加一個私有變量的對象?public?void?AddLogger(){_logger.AddLogger();} }

最后,控制臺調用輸出:

????static?void?Main(string[]?args){LoggerServer?loggerServer?=?new?LoggerServer();loggerServer.AddLogger();Console.Read();} ?

「控制臺輸出:日志新增成功!」

?

雖然第二種方式中,采用了接口來實現,降低耦合,但還是沒有達到我們想要的效果,因此以上的兩種方式,都不是很好的軟件設計方式。

代碼可拓展性比較差,以及組件之間存在高度耦合,違反了開放關閉原則,在設計的時候,也應當考慮「對擴展開放,對修改關閉」

2.3 思考

既然要遵循開放關閉原則,那上面的寫法,選擇采用控制臺日志輸出方式所需要的ConsoleLogger創建和依賴都是在統一的日志類LoggerServer內部進行的,既然要使內部不直接存在綁定依賴,那有沒有什么方式從外部傳遞的方式給LoggerServer類內部引用使用呢?

三、引入

3.1 依賴注入

「依賴注入」 : 它提供一種機制,將需要依賴對象的引用傳遞給被依賴對象。

下面我們先看看具體的幾種注入方式,再做小結說明。

3.1.1 構造函數注入

在LoggerServer類中,定義一個私有變量_logger, 然后通過構造函數的方式傳遞依賴

public?class?LoggerServer {private?ILogger?_logger;?//1.?定義私有變量//2.構造函數public?LoggerServer(ILogger?logger){//3.注入?,傳遞依賴this._logger?=?logger;?}public?void?AddLogger(){_logger.AddLogger();} }

通過控制臺程序調用,先在外部創建依賴對象,而后通過構造的方式注入依賴

????????static?void?Main(string[]?args){#region?構造函數注入//?注入控制臺輸出方式//?外部創建依賴的對象?->?ConsoleLoggerConsoleLogger?console?=?new?ConsoleLogger();//?通過構造函數注入?->?LoggerServerLoggerServer?loggerServer1?=?new?LoggerServer(console);loggerServer1.AddLogger();//?注入?文件輸出方式FileLogger?file?=?new?FileLogger();//?通過構造函數注入?->?LoggerServerLoggerServer?loggerServer2?=?new?LoggerServer(file);loggerServer2.AddLogger();#endregionConsole.Read();}

輸出:

?

控制臺輸出:日志新增成功!

文本輸出:日志新增成功!

?

顯然的發現,通過這種構造函數注入的方式,在外部定義依賴,降低內部的耦合度,同時也增加了擴展性,只需從外部修改依賴,就可以實現不同的驗證結果。

3.1.2 屬性注入

即通過定義一個屬性來傳遞依賴

????///?<summary>///?定義一個輸出日志的統一類///?</summary>public?class?LoggerServer{//1.定義一個屬性,可接收外部賦值依賴public?ILogger?_logger?{?get;?set;?}public?void?AddLogger(){_logger.AddLogger();}}

通過控制臺,定義不同的方式,通過不同依賴賦值,實現不同的驗證結果:

????????static?void?Main(string[]?args){#region?屬性注入//?注入?控制臺輸出方式//外部創建依賴的對象?->?ConsoleLoggerConsoleLogger?console?=?new?ConsoleLogger();LoggerServer?loggerServer1?=?new?LoggerServer();//給內部的屬性賦值loggerServer1._logger?=?console;loggerServer1.AddLogger();//?注入?文件輸出方式//外部創建依賴的對象?->?FileLoggerFileLogger?file?=?new?FileLogger();LoggerServer?loggerServer2?=?new?LoggerServer();//給內部的屬性賦值loggerServer2._logger?=?file;loggerServer2.AddLogger();#endregionConsole.Read();}

輸出

?

控制臺輸出:日志新增成功!

文本輸出:日志新增成功!

?

3.1.3 接口注入

先定義一個接口,包含一個設置依賴的方法。

????public?interface?IDependent{void?SetDepend(ILogger?logger);//設置依賴項}

這個與之前的注入方式不一樣,而是通過在類中「繼承并實現這個接口」

????public?class?VerificationServer?:?IDependent{private?ILogger?_logger;//?繼承接口,并實現依賴項方法,注入依賴public?void?SetDepend(ILogger?logger){_logger?=?logger;}public?void?AddLogger(){_logger.AddLogger();}}

通過調用,直接通過依賴項方法,傳遞依賴

????????static?void?Main(string[]?args){#region?接口注入//?注入?控制臺輸出方式//外部創建依賴的對象?->?ConsoleLoggerConsoleLogger?console?=?new?ConsoleLogger();LoggerServer?loggerServer1?=?new?LoggerServer();//給內部賦值,通過接口的方式傳遞loggerServer1.SetDepend(console);loggerServer1.AddLogger();//注入??文件輸出方式//外部創建依賴的對象?->?FileLoggerFileLogger?file?=?new?FileLogger();LoggerServer?loggerServer2?=?new?LoggerServer();//給內部賦值,通過接口的方式傳遞loggerServer2.SetDepend(file);loggerServer2.AddLogger();#endregionConsole.Read();}

輸出

?

控制臺輸出:日志新增成功!

文本輸出:日志新增成功!

?

3.1.4 小結

「依賴注入(DI—Dependency Injection)」

「它提供一種機制,將需要依賴對象的引用傳遞給被依賴對象」通過DI,我們可以在LoggerServer類在外部ConsoleLogger對象的引用傳遞給LoggerServer類對象。 注入某個對象所需要的外部資源(包括對象、資源、常量數據)

?

依賴注入把對象的創造交給外部去管理,很好的解決了代碼緊耦合的問題,是一種讓代碼實現松耦合的機制。 松耦合讓代碼更具靈活性,能更好地應對需求變動,以及方便單元測試。

?

3.2 IOC

「控制反轉」(Inversion of Control,縮寫為「IoC」),在面向對象編程中,是一種「軟件設計模式」,教我們如何設計出更優良,更具有松耦合的程序。

在上文的例子中,我們發現如果在獲取對象的過程中靠類內部主動創建依賴對象,則會導致代碼直接高度耦合并且期存在難以維護這種隱患,所以為了避免這種問題,我們采用了由外部提供依賴對象,內部對象類被創建的時候,將其所依賴的對象引用傳遞給它,實現了依賴被注入到對象中去。

?

通俗的說明:

在類A中用到了類B的對象時候,一般情況下,需要在A的代碼中顯式的new一個B的對象。這種方式都是通過我們自己主動創建出來的,創建合作對象的主動權在自己手上,自己需要哪個對象,就主動去創建,創建對象的主動權和創建時機是由自己把控的,而這樣就會使得對象間的耦合度高了,A對象需要使用對象B來共同完成一件事,A要使用B,那么A就對B產生了依賴,也就是A和B之間存在一種耦合關系,并且是緊密耦合在一起。

public?class?A { private?B?b?=?new?B();//主動的new一個B的對象。主動創建出來 public?void?Get() {B.Create(); } }

采用依賴注入技術之后,A的代碼只需要定義一個私有的B對象,不需要直接new來獲得這個對象,而是通過相關的容器控制程序來將B對象在外部new出來并注入到A類里的引用中。現在創建對象而是有第三方控制創建,你要什么對象,它就給你什么對象,依賴關系就變了,原先的依賴關系就沒了,A和B之間耦合度也就減少了。

public?class?A { private?B?b;//外部new出來,?注入到引用中 public?void?Get() {B.Create(); } } ?

3.3 關系

「控制反轉(IoC)」 是一種軟件設計的模式,指導我們設計出更優良,更具有松耦合的程序,

而具體的實現方式有「依賴注入」「依賴查找」

在這一篇主要說的是常用的「依賴注入」方式。

你在實際開發中,可能還會聽到另一名詞叫 「IoC容器」,這其實是一個依賴注入的「框架」

用來映射依賴,管理對象創建和生存周期。 (在后續篇章會具體說明)

四、思考

說到依賴,就想到依賴注入和工廠模式這兩者的區別?

這是網上有一個對比例子:


工廠設計模式依賴注入
對象創建它用于創建對象。我們有單獨的Factory類,其中包含創建邏輯。它負責創建和注入對象。
對象的狀態它負責創建有狀態對象。負責創建無狀態對象
運行時/編譯時間在編譯時創建對象在運行時配置對象
代碼變更如果業務需求發生變化,則可能會更改對象創建邏輯。無需更改代碼
機制類依賴于工廠方法,而工廠方法又依賴于具體類父對象和所有從屬對象可以在單個位置創建

好啦,這篇文章就先講述到這里吧,「在后續篇章中會對常用的IOC容器進行使用說明」,希望對大家有所幫助。

如果有不對的或不理解的地方,希望大家可以多多指正,提出問題,一起討論,不斷學習,共同進步。????

總結

以上是生活随笔為你收集整理的谈谈对IOC及DI的理解与思考的全部內容,希望文章能夠幫你解決所遇到的問題。

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