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

1. 何為依賴倒置原則

定義:高層模塊不應(yīng)該依賴于低層模塊,二者都應(yīng)該依賴于抽象;抽象不應(yīng)該依賴細節(jié);細節(jié)應(yīng)該依賴抽象。

定義解讀:

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

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

依賴倒轉(zhuǎn)原則其實可以說是面向?qū)ο笤O(shè)計的標志,用哪種語言來編寫程序不重要,如果編寫時考慮的都是如何針對抽象編程而不是針對細節(jié)編程,即程序中所有的依賴關(guān)系都是終止于抽象類或者接口,那就是面向?qū)ο蟮脑O(shè)計,反之那就是過程化的設(shè)計(說這句話可能不怎么好理解,再加上一句話就好理解了:面向?qū)ο蟮脑O(shè)計,出發(fā)點就是應(yīng)對變化的問題)。

再舉一個生活中的例子,電腦中內(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)點:代碼結(jié)構(gòu)清晰,維護容易。

2. 情景設(shè)置

類A直接依賴類B,假如需要將類A改為依賴類C,則必須通過修改類A的代碼來達成。這種場景下,類A一般是高層模塊,負責(zé)復(fù)雜的業(yè)務(wù)邏輯;類B和類C是低層模塊,負責(zé)基本的原子操作;假如修改類A,會給程序帶來不必要的風(fēng)險。

解決方案

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

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

3. 代碼示例

繼續(xù)發(fā)工資的場景:這里,類SalaryManage(類似上面說的類A)負責(zé)工資的管理;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)客戶端調(diào)用

/* 原始做法
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)在假設(shè)需要給經(jīng)理發(fā)工資,我們發(fā)現(xiàn)工資管理類SalaryManage沒法直接完成這個功能,需要我們添加新的方法,才能完成。再假設(shè)我們還需要給普通員工、財務(wù)總監(jiān)、研發(fā)總監(jiān)等更多的崗位發(fā)送工資,那么我們就只能不斷的去修改SalaryManage類來滿足業(yè)務(wù)的需求。產(chǎn)生這種現(xiàn)象的原因就是SalaryManage與Director之間的耦合性太高了,必須降低它們之間的耦合度才行。因此我們引入一個委托EmployeeDelegate,它提供一個發(fā)放工資的方法定義,然后我們讓具體的員工類Director、Manager等都實現(xiàn)該委托方法。

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

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容