六驾诈、設計模式的六大設計原則之依賴倒置原則(DIP, Dependence Inversion Principle)

1. 何為依賴倒置原則

定義:高層模塊不應該依賴于低層模塊缠诅,二者都應該依賴于抽象;抽象不應該依賴細節(jié)乍迄;細節(jié)應該依賴抽象管引。

定義解讀:

依賴倒置原則在程序編碼中經(jīng)常運用,其核心思想就是面向接口編程闯两,高層模塊不應該依賴低層模塊(原子操作的模塊)褥伴,兩者都應該依賴于抽象。我們平時常說的“針對接口編程漾狼,不要針對實現(xiàn)編程”就是依賴倒轉原則的最好體現(xiàn):接口(也可以是抽象類)就是一種抽象重慢,只要不修改接口聲明,大家可以放心大膽調用邦投,至于接口的內(nèi)部實現(xiàn)則無需關心伤锚,可以隨便重構。這里志衣,接口就是抽象屯援,而接口的實現(xiàn)就是細節(jié)。

如果不管高層模塊還是底層模塊念脯,它們都依賴于抽象狞洋,具體一點就是接口或者抽象類,只要接口是穩(wěn)定的绿店,那么任何一個的更改都不用擔心其他受到影響吉懊,這就使得無論高層模塊還是低層模塊都可以很容易地被復用。

依賴倒轉原則其實可以說是面向對象設計的標志假勿,用哪種語言來編寫程序不重要借嗽,如果編寫時考慮的都是如何針對抽象編程而不是針對細節(jié)編程,即程序中所有的依賴關系都是終止于抽象類或者接口转培,那就是面向對象的設計恶导,反之那就是過程化的設計(說這句話可能不怎么好理解,再加上一句話就好理解了:面向對象的設計浸须,出發(fā)點就是應對變化的問題)惨寿。

再舉一個生活中的例子邦泄,電腦中內(nèi)存或者顯卡插槽,其實是一種接口裂垦,而這就是抽象顺囊;只要符合這個接口的要求,無論是用金士頓的內(nèi)存蕉拢,還是其它的內(nèi)存特碳,無論是4G的,還是8G的企量,都可以很方便测萎、輕松的插到電腦上使用亡电。而這些內(nèi)存條就是具體實現(xiàn)届巩,就是細節(jié)。

錯誤做法:抽象A依賴于實現(xiàn)細節(jié)b份乒,如圖1-1所示:

圖1-1

正確做法:抽象A依賴于抽象B恕汇,實現(xiàn)細節(jié)b實現(xiàn)抽象B,如圖1-2所示:

圖1-2

優(yōu)點:代碼結構清晰或辖,維護容易瘾英。

2. 情景設置

類A直接依賴類B,假如需要將類A改為依賴類C颂暇,則必須通過修改類A的代碼來達成缺谴。這種場景下,類A一般是高層模塊耳鸯,負責復雜的業(yè)務邏輯湿蛔;類B和類C是低層模塊,負責基本的原子操作县爬;假如修改類A阳啥,會給程序帶來不必要的風險。

解決方案

將類A修改為依賴接口I财喳,類B和類C各自實現(xiàn)接口I察迟,類A通過接口I間接與類B或者類C發(fā)生聯(lián)系,則會大大降低修改類A的幾率耳高。

依賴倒置原則基于這樣一個事實:相對于細節(jié)的多變性扎瓶,抽象的東西要穩(wěn)定的多。以抽象為基礎搭建起來的架構比以細節(jié)為基礎搭建起來的架構要穩(wěn)定的多泌枪。在C#/Java中概荷,抽象指的是接口或者抽象類;在Objective-C中工闺,抽象指的是委托乍赫,細節(jié)就是具體的實現(xiàn)類瓣蛀,使用接口或者抽象類的目的是制定好規(guī)范和契約,而不去涉及任何具體的操作雷厂,把展現(xiàn)細節(jié)的任務交給它們的實現(xiàn)類去完成惋增。

3. 代碼示例

繼續(xù)發(fā)工資的場景:這里,類SalaryManage(類似上面說的類A)負責工資的管理改鲫;Director(類似上面說的類B)是總監(jiān)類诈皿,現(xiàn)在我們要通過SalaryManage類來給總監(jiān)發(fā)放工資了,主要代碼片段如下所示:

(1)EmployeeDelegate

@protocol EmployeeDelegate <NSObject>

- (void)calculateSalary;

@end

(2)Director

@interface Director : NSObject<EmployeeDelegate>

@property(nonatomic, copy) NSString *strName;  // 姓名

//- (void)calculateSalary;

@end


@implementation Director

@synthesize strName = _strName;

- (void)calculateSalary
{
    NSLog(@"%@總監(jiān)的工資是10000",_strName);
}
@end

(3)Manager

@interface Manager : NSObject<EmployeeDelegate>

@property(nonatomic, copy) NSString *strName;  // 姓名

//- (void)calculateSalary;

@end



@implementation Manager

@synthesize strName = _strName;

- (void)calculateSalary
{
    NSLog(@"%@經(jīng)理的工資是1000",_strName);
}
@end

(4)SalaryManage

@interface SalaryManage : NSObject

//- (void)calculateSalary:(Director *)director;  // 原始做法
- (void)calculateSalary:(id<EmployeeDelegate>)employee;  // 遵守依賴倒置原則的做法

@end


@implementation SalaryManage

/*
- (void)calculateSalary:(Director *)director
{
    [director calculateSalary];
}
 */

- (void)calculateSalary:(id<EmployeeDelegate>)employee
{
    [employee calculateSalary];
}

@end

(5)客戶端調用

/* 原始做法
Director *director = [[Director alloc] init];
director.strName  = @"張三";
SalaryManage *salaryManage = [[SalaryManage alloc] init];
[salaryManage calculateSalary:director];
*/
       
// 遵守依賴倒置原則的做法
Director *director = [[Director alloc] init];
director.strName  = @"張三";
 Manager *manager = [[Manager alloc] init];
manager.strName  = @"李四";
SalaryManage *salaryManage = [[SalaryManage alloc] init];
[salaryManage calculateSalary:director];
[salaryManage calculateSalary:manager];

這樣給總監(jiān)發(fā)放工資的功能已經(jīng)很好的實現(xiàn)了像棘,現(xiàn)在假設需要給經(jīng)理發(fā)工資稽亏,我們發(fā)現(xiàn)工資管理類SalaryManage沒法直接完成這個功能,需要我們添加新的方法缕题,才能完成截歉。再假設我們還需要給普通員工、財務總監(jiān)烟零、研發(fā)總監(jiān)等更多的崗位發(fā)送工資瘪松,那么我們就只能不斷的去修改SalaryManage類來滿足業(yè)務的需求。產(chǎn)生這種現(xiàn)象的原因就是SalaryManage與Director之間的耦合性太高了锨阿,必須降低它們之間的耦合度才行宵睦。因此我們引入一個委托EmployeeDelegate,它提供一個發(fā)放工資的方法定義墅诡,然后我們讓具體的員工類Director壳嚎、Manager等都實現(xiàn)該委托方法。

這樣修改后末早,無論以后怎樣擴展其他的崗位烟馅,都不需要再修改SalaryManage類了。代表高層模塊的SalaryManage類將負責完成主要的業(yè)務邏輯(發(fā)工資)荐吉,如果需要對SalaryManage類進行修改焙糟,引入錯誤的風險極大。所以遵循依賴倒置原則可以降低類之間的耦合性样屠,提高系統(tǒng)的穩(wěn)定性穿撮,降低修改程序造成的風險。

同樣痪欲,采用依賴倒置原則給多人并行開發(fā)帶來了極大的便利悦穿,比如在上面的例子中,剛開始SalaryManage類與Director類直接耦合時业踢,SalaryManage類必須等Director類編碼完成后才可以進行編碼和測試栗柒,因為SalaryManage類依賴于Director類。按照依賴倒置原則修改后,則可以同時開工瞬沦,互不影響太伊,因為SalaryManage與Director類一點關系也沒有,只依賴于協(xié)議(Java和C#中稱為接口)EmployeeDelegate逛钻。參與協(xié)作開發(fā)的人越多僚焦、項目越龐大,采用依賴導致原則的意義就越重大曙痘。

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末芳悲,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子边坤,更是在濱河造成了極大的恐慌名扛,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,602評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件茧痒,死亡現(xiàn)場離奇詭異肮韧,居然都是意外死亡,警方通過查閱死者的電腦和手機文黎,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評論 2 382
  • 文/潘曉璐 我一進店門惹苗,熙熙樓的掌柜王于貴愁眉苦臉地迎上來殿较,“玉大人耸峭,你說我怎么就攤上這事×芨伲” “怎么了劳闹?”我有些...
    開封第一講書人閱讀 152,878評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長洽瞬。 經(jīng)常有香客問我本涕,道長,這世上最難降的妖魔是什么伙窃? 我笑而不...
    開封第一講書人閱讀 55,306評論 1 279
  • 正文 為了忘掉前任菩颖,我火速辦了婚禮,結果婚禮上为障,老公的妹妹穿的比我還像新娘晦闰。我一直安慰自己,他們只是感情好鳍怨,可當我...
    茶點故事閱讀 64,330評論 5 373
  • 文/花漫 我一把揭開白布呻右。 她就那樣靜靜地躺著,像睡著了一般鞋喇。 火紅的嫁衣襯著肌膚如雪声滥。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,071評論 1 285
  • 那天侦香,我揣著相機與錄音落塑,去河邊找鬼纽疟。 笑死,一個胖子當著我的面吹牛憾赁,可吹牛的內(nèi)容都是我干的仰挣。 我是一名探鬼主播,決...
    沈念sama閱讀 38,382評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼缠沈,長吁一口氣:“原來是場噩夢啊……” “哼膘壶!你這毒婦竟也來了?” 一聲冷哼從身側響起洲愤,我...
    開封第一講書人閱讀 37,006評論 0 259
  • 序言:老撾萬榮一對情侶失蹤颓芭,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后柬赐,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體亡问,經(jīng)...
    沈念sama閱讀 43,512評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,965評論 2 325
  • 正文 我和宋清朗相戀三年肛宋,在試婚紗的時候發(fā)現(xiàn)自己被綠了州藕。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,094評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡酝陈,死狀恐怖床玻,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情沉帮,我是刑警寧澤锈死,帶...
    沈念sama閱讀 33,732評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站穆壕,受9級特大地震影響待牵,放射性物質發(fā)生泄漏。R本人自食惡果不足惜喇勋,卻給世界環(huán)境...
    茶點故事閱讀 39,283評論 3 307
  • 文/蒙蒙 一缨该、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧川背,春花似錦贰拿、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,286評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至皱碘,卻和暖如春询一,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,512評論 1 262
  • 我被黑心中介騙來泰國打工健蕊, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留菱阵,地道東北人。 一個月前我還...
    沈念sama閱讀 45,536評論 2 354
  • 正文 我出身青樓缩功,卻偏偏與公主長得像晴及,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子嫡锌,可洞房花燭夜當晚...
    茶點故事閱讀 42,828評論 2 345

推薦閱讀更多精彩內(nèi)容