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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【简译】关于依赖反转原则、控制反转和依赖注入的抽象的初学者指南

發(fā)布時間:2025/5/22 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【简译】关于依赖反转原则、控制反转和依赖注入的抽象的初学者指南 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

原文在此。

======================================分割線====================================

介紹

文章以介紹依賴反轉(zhuǎn)原則開始,接下來介紹如何使用控制反轉(zhuǎn)來實現(xiàn)依賴反轉(zhuǎn)原則,最后將闡述什么是依賴注入和如何實現(xiàn)它。

背景

在我們開始講依賴注入前,首先要了解依賴注入要解決的問題。為了理解這個問題,我們需要知道兩個事情:一,依賴反轉(zhuǎn)原則;二,控制反轉(zhuǎn)(Inversion of Controls(IoC)。我們先討論依賴反轉(zhuǎn)原則然后講IoC。一旦完成這兩個,我們就可以更好地理解依賴注入,然后我們就可以一窺依賴注入的細(xì)節(jié)。最后我們討論如何實現(xiàn)依賴注入。

依賴反轉(zhuǎn)原則

依賴反轉(zhuǎn)原則是一個指導(dǎo)我們寫出松耦合類的軟件設(shè)計原則。根據(jù)依賴反轉(zhuǎn)原則的定義:
1. 高層模塊不應(yīng)該以依賴低層模塊。他們都應(yīng)該依賴抽象層。

2.抽象層不應(yīng)該依賴細(xì)節(jié),細(xì)節(jié)應(yīng)該依賴抽象層。

這個定義是什么意思?它想傳達(dá)什么?讓我們通過例子理解這個。幾年前我被委派寫一個本應(yīng)該運行在web server的windows service。這個service唯一的需求是無論何時在IIS應(yīng)用程序池出現(xiàn)錯誤就要在事件日志上登記消息。我們團(tuán)隊最初的實現(xiàn)是生成兩個類。一個監(jiān)視這個應(yīng)用程序池,另一個寫在事件日志里寫消息。我們的類看起來像這樣:

class EventLogWriter {public void Write(string message){//Write to event log here } }class AppPoolWatcher {// Handle to EventLog writer to write to the logsEventLogWriter writer = null;// This function will be called when the app pool has problempublic void Notify(string message){if (writer == null){writer = new EventLogWriter();}writer.Write(message);} }

它看起來很好,但是有問題,這個設(shè)計違反了依賴反轉(zhuǎn)原則。例如,高層模塊 AppPoolWatcher?依賴EventLogWriter ,EventLogWriter?不是一個抽象而是一個具體類。讓我告訴你我們收到的關(guān)于這個service的下一個需求,問題就變得明朗。

下一個需求是向網(wǎng)絡(luò)管理員的email發(fā)送關(guān)于指定的錯誤的郵件。一個想法是生成一個發(fā)送郵件的類并且把他的handle放到?AppPoolWatcher?但是在任意時刻我們只能使用一個對象,要么是?EventLogWriter 要么是?EmailSender?

一旦我們有更多可選的動作,像發(fā)送SMS,問題就變得更加嚴(yán)重。那樣,我們就不得不添加一個實例保存在?AppPoolWatcher?的類。依賴反轉(zhuǎn)原則告訴我們,我們需要解耦這個系統(tǒng),方法是高級模塊在我們的例子中是?AppPoolWatcher?將依賴一個簡單的抽象并使用它。這個抽象反過來將被映射到一些會執(zhí)行實際操作的具體類上。

控制反轉(zhuǎn)

依賴反轉(zhuǎn)是原則,他只是指明兩個模塊如何相互依賴。控制反轉(zhuǎn)來實現(xiàn)他。控制反轉(zhuǎn)使得我們可以使高層模塊依賴抽象而不是底層模塊的具體實現(xiàn)。

為了使用控制反轉(zhuǎn)實現(xiàn)上述問題方案,第一步,我們需要創(chuàng)建一個抽象讓高層模塊可以依賴。我們創(chuàng)建一個接口來提供這個抽象。這個接口實現(xiàn)從 AppPoolWatcher?收到的通知。

?

public interface INofificationAction {public void ActOnNotification(string message); }

?

修改高層模塊來使用這個抽象

class AppPoolWatcher {// Handle to EventLog writer to write to the logsINofificationAction action = null;// This function will be called when the app pool has problempublic void Notify(string message){if (action == null){// Here we will map the abstraction i.e. interface to concrete class }action.ActOnNotification(message);} }

低層模塊如何修改,我們需要實現(xiàn)上面的接口在這個類中使得他符合抽象。

class EventLogWriter : INofificationAction { public void ActOnNotification(string message){// Write to event log here } }

如果我要發(fā)送email和sms,這些類只要實現(xiàn)相同的接口就可以了:

class EmailSender : INofificationAction {public void ActOnNotification(string message){// Send email from here } }class SMSSender : INofificationAction {public void ActOnNotification(string message){// Send SMS from here } }

類的最終設(shè)計像下圖一樣:

這里,我們已經(jīng)反轉(zhuǎn)了控制去符合依賴反轉(zhuǎn)原則。現(xiàn)在我們的高層模塊只依靠抽象,這正是依賴反轉(zhuǎn)原則表明的。

但仍然有問題。觀察AppPoolWatcher,我們可以看到雖然它使用接口作為抽象但是我們創(chuàng)建了具體類型并賦值給了這個抽象。為了解決這個問題,我們可以:

class AppPoolWatcher {// Handle to EventLog writer to write to the logsINofificationAction action = null;// This function will be called when the app pool has problempublic void Notify(string message){if (action == null){// Here we will map the abstraction i.e. interface to concrete class writer = new EventLogWriter();}action.ActOnNotification(message);} }

但是我們有回到原點了。具體類的創(chuàng)建還是在高層類里。依賴注入進(jìn)入眼簾。是時候介紹依賴注入的細(xì)節(jié)了。

依賴注入

依賴注入主要是注入具體實現(xiàn)到一個使用抽象例如接口的類里面。他的主要思想是減少類之間的耦合和移動抽象和具體實現(xiàn)之間的綁定到依賴?yán)椎耐饷妗?/p>

有三個方式實現(xiàn)依賴注入:

  • Constructor injection
  • Method injection
  • Property injection
  • ?Constructor injection(構(gòu)造函數(shù)注入)

    在這個方法里,我們傳遞具體類對象到依賴類的構(gòu)造函數(shù)里。在依賴類中我們需要一個可以獲取具體類對象的構(gòu)造函數(shù)并把這個具體類賦值給這個類正在使用的接口handle,用此方法實現(xiàn)構(gòu)造函數(shù)注入。代碼如下:

    class AppPoolWatcher {// Handle to EventLog writer to write to the logsINofificationAction action = null;public AppPoolWatcher(INofificationAction concreteImplementation){this.action = concreteImplementation;}// This function will be called when the app pool has problempublic void Notify(string message){ action.ActOnNotification(message);} }

    在上面的代碼中,構(gòu)造函數(shù)將接受具體類對象并和接口handle綁定。如果我們要傳EventLogWriter的具體實現(xiàn)到這個類中,我們要:

    EventLogWriter writer = new EventLogWriter(); AppPoolWatcher watcher = new AppPoolWatcher(writer); watcher.Notify("Sample message to log");

    如果像發(fā)送email或SMS,我們只需要傳遞各自類對象到AppPoolWatcher的構(gòu)造函數(shù)里。當(dāng)我們知道這個依賴類的實例將在整個生命期一直使用一樣的具體類,這個方法是有用的。

    Method Injection

    如果我們想傳遞單獨的具體類都每個方法調(diào)用中,我們只需要傳遞依賴到這個方法里。

    在方法注入里,我們傳具體類對象到實際調(diào)用這個動作的依賴類的方法里。我們需要這個動作函數(shù)接受具體類對象的實參并賦值個這個類正在使用接口handle同時調(diào)用這個動作。代碼如下:

    class AppPoolWatcher {// Handle to EventLog writer to write to the logsINofificationAction action = null;// This function will be called when the app pool has problempublic void Notify(INofificationAction concreteAction, string message){this.action = concreteAction;action.ActOnNotification(message);} }

    如果我們要傳EventLogWriter的具體實現(xiàn)到這個類,只要:

    EventLogWriter writer = new EventLogWriter(); AppPoolWatcher watcher = new AppPoolWatcher(); watcher.Notify(writer, "Sample message to log");

    ?

    如果像發(fā)送email或SMS,我們只需要像上面一樣傳遞各自類對象到AppPoolWatcher的調(diào)用方法里。

    property injection

    ?

    如果具體類的選擇的責(zé)任和調(diào)用的方法不在一個地方。我們需要屬性注入

    在這個方式里,我們通過依賴類暴露的setter屬性傳遞具體類對象。我們通過使用在依賴類的setter屬性或函數(shù)來獲取具體類對象并賦值給這個類正在使用的接口handle。代碼如下:

    class AppPoolWatcher {// Handle to EventLog writer to write to the logsINofificationAction action = null;public INofificationAction Action{get{return action;}set{action = value;}}// This function will be called when the app pool has problempublic void Notify(string message){ action.ActOnNotification(message);} }

    如果要傳EventLogWriter具體實現(xiàn)到這個類中,我們只需:

    EventLogWriter writer = new EventLogWriter(); AppPoolWatcher watcher = new AppPoolWatcher(); // This can be done in some class watcher.Action = writer;// This can be done in some other class watcher.Notify("Sample message to log");

    如果像發(fā)送email或SMS,我們只需要像上面一樣傳遞各自類對象到AppPoolWatcher暴露的setter中里。當(dāng)選擇的具體實現(xiàn)的職責(zé)和調(diào)用的完成的動作在不同的位置/模塊。

    在沒有支持屬性的語言里,有單獨的函數(shù)設(shè)置依賴。這個方法叫做setter 注入。需要注意的是,有可能有些人已經(jīng)創(chuàng)建了依賴類(dependent class),但是沒有人設(shè)置具體類依賴(dependency)。如果我們試圖調(diào)用在這種情況下調(diào)用這個動作,那我們應(yīng)該要么有一些映射到依賴類(dependent class)的默認(rèn)依賴(dependency),要么有一些機(jī)制確保應(yīng)用行為正確。

    關(guān)于IoC Containers

    構(gòu)造函數(shù)注入是實現(xiàn)依賴注入最廣泛使用的方法,如果需要傳遞不同的依賴(dependencies)在每個方法調(diào)用里,我們使用方法注入。屬性注入使用的頻率少一些。

    如果我們只有一級的依賴(dependency),上面的方法可以工作的很好。但是如果具體類是其他抽象的依賴又如何。如果我們嵌套或鏈接依賴(dependencies),那實現(xiàn)依賴注入會有點復(fù)雜。這時可以使用IoC containers。IoC containers 可以容易的映射依賴(dependencies)當(dāng)我們嵌套或鏈接依賴(dependencies)。

    ?

    轉(zhuǎn)載于:https://www.cnblogs.com/muzinian/p/3357741.html

    總結(jié)

    以上是生活随笔為你收集整理的【简译】关于依赖反转原则、控制反转和依赖注入的抽象的初学者指南的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。