六大設(shè)計原則之五:迪米特法則

定義

迪米特法則(Law of Demeter, LoD)是1987年秋天由lan holland在美國東北大學(xué)一個叫做迪米特的項目設(shè)計提出的,它要求一個對象應(yīng)該對其他對象有最少的了解洲赵,所以迪米特法則又叫做最少知識原則(Least Knowledge Principle, LKP)睛驳。

意義

迪米特法則的意義在于降低類之間的耦合辜梳。由于每個對象盡量減少對其他對象的了解泊柬,因此蜜唾,很容易使得系統(tǒng)的功能模塊功能獨立杂曲,相互之間不存在(或很少有)依賴關(guān)系。

值得一提的是袁余,這一法則卻不僅僅局限于計算機(jī)領(lǐng)域擎勘,在其他領(lǐng)域也同樣適用。比如颖榜,美國人就在航天系統(tǒng)的設(shè)計中采用這一法則棚饵。

實踐

那么在實踐中如何做到一個對象應(yīng)該對其他對象有最少的了解呢?如果我們把一個對象看作是一個人掩完,那么要實現(xiàn)“一個人應(yīng)該對其他人有最少的了解”噪漾,做到兩點就足夠了:1.只和直接的朋友交流;2.減少對朋友的了解且蓬。下面就詳細(xì)說說如何做到這兩點欣硼。

只和直接的朋友交流

迪米特法則還有一個英文解釋是:talk only to your immediate friends(只和直接的朋友交流)。什么是朋友呢恶阴?每個對象都必然會與其他的對象有耦合關(guān)系诈胜,兩個對象之間的耦合就會成為朋友關(guān)系。那么什么又是直接的朋友呢冯事?出現(xiàn)在成員變量焦匈、方法的輸入輸出參數(shù)中的類就是直接的朋友。迪米特法則要求只和直接的朋友通信昵仅。

注意:
只出現(xiàn)在方法體內(nèi)部的類就不是直接的朋友缓熟,如果一個類和不是直接的朋友進(jìn)行交流,就屬于違反迪米特法則。

我們舉一個例子說明什么是朋友够滑,什么是直接的朋友垦写。很簡單的例子:老師讓班長清點全班同學(xué)的人數(shù)。這個例子中總共有三個類:老師Teacher版述、班長GroupLeader和學(xué)生Student梯澜。

老師類:

@interface Teacher : NSObject

//命令班長清點人數(shù)
- (void)command:(GroupLeader *)groupLeader;

@end

@implementation Teacher

- (void)command:(GroupLeader *)groupLeader{

    //創(chuàng)建全班學(xué)生的數(shù)組
    NSMutableArray<Student *> *students = [[NSMutableArray alloc] init];
    for (int i = 0; i < 20; i++) {
        Student *student = [[Student alloc] init];
        [students addObject:student];
    }

    //讓班長清點人數(shù)
    [groupLeader count:students];
}

@end

班長類:

@interface GroupLeader : NSObject

//清點人數(shù)
- (void)count:(NSArray<Student *> *)students;

@end

@implementation GroupLeader

- (void)count:(NSArray<Student *> *)students{
    //直接打印出學(xué)生的人數(shù)
    NSLog(@"上課人數(shù)是:%d",(int)students.count);
}

@end

學(xué)生類:

@interface Student : NSObject

@end

@implementation Student

@end

使用場景也是非常的簡單:

int main(int argc, const char * argv[]) {

    //創(chuàng)建班長對象
    GroupLeader *groupLeader = [[GroupLeader alloc] init];

    //創(chuàng)建老師對象
    Teacher *teacher = [[Teacher alloc] init];
    
    //老師命令班長清點人數(shù)
    [teacher command:groupLeader];

    return 0;
}

在這個例子中,我們的Teacher有幾個朋友渴析?兩個晚伙,一個是GroupLeader,因為它是Teachercommand:方法的輸入?yún)?shù)俭茧;另一個是Student咆疗,因為在Teachercommand:方法體中使用了Student

那么我們的Teacher有幾個是直接的朋友母债?按照直接的朋友的定義“出現(xiàn)在成員變量午磁、方法的輸入輸出參數(shù)中的類就是直接的朋友”,只有GroupLeaderTeacher的直接的朋友毡们。

Teachercommand方法中創(chuàng)建了Student的數(shù)組迅皇,和非直接的朋友Student發(fā)生了交流,所以衙熔,上述例子違反了迪米特法則登颓。方法是類的一個行為,類竟然不知道自己的行為與其他的類產(chǎn)生了依賴關(guān)系红氯,這是不允許的框咙,嚴(yán)重違反了迪米特法則!

為了使上述例子符合迪米特法則痢甘,我們可以做如下修改:

修改后的GroupLeader:

@interface GroupLeader : NSObject

//構(gòu)造方法喇嘱,傳入全班學(xué)生數(shù)組
- (instancetype)initWithStudents:(NSArray<Student *> *)students;

//清點人數(shù)方法
- (void)count;

@end

@implementation GroupLeader
{
    NSArray<Student *> *_students;
}

- (instancetype)initWithStudents:(NSArray<Student *> *)students{

    self = [super init];
    if (self) {
        _students = students;
    }
    return self;
}

- (void)count{
    NSLog(@"上課人數(shù)是:%d",(int)_students.count);
}

@end

修改后的老師類:

@interface Teacher : NSObject

//命令班長執(zhí)行清點人數(shù)的任務(wù)
- (void)command:(GroupLeader *)groupLeader;

@end

@implementation Teacher

- (void)command:(GroupLeader *)groupLeader{

    [groupLeader count];
}

@end

修改后的使用場景:

int main(int argc, const char * argv[]) {

    //創(chuàng)建學(xué)生數(shù)組
    NSMutableArray *students = [[NSMutableArray alloc] init];
    for (int i = 0; i < 20; i++) {
        Student *student = [[Student alloc] init];
        [students addObject:student];
    }
    
    //創(chuàng)建班長
    GroupLeader *groupLeader = [[GroupLeader alloc] initWithStudents:students];

    //創(chuàng)建老師
    Teacher *teacher = [[Teacher alloc] init];
    
    //老師命令班長執(zhí)行清點人數(shù)命令
    [teacher command:groupLeader];

    return 0;
}

這樣修改后,每個類都只和直接的朋友交流塞栅,有效減少了類之間的耦合者铜。

減少對朋友的了解

如何減少對朋友的了解?如果你的朋友是個話癆加大喇叭放椰,那就算你不主動去問他作烟,他也會在你面前叨叨叨,把他所有的經(jīng)歷都講給你聽庄敛。所以,要減少對朋友的了解科汗,請換一個內(nèi)斂一點的朋友吧~換作在一個類中藻烤,就是盡量減少一個類對外暴露的方法

舉一個簡單的例子說明一個類暴露方法過多的情況。這個例子描述的是一個人用咖啡機(jī)煮咖啡的過程怖亭,例子中只有兩個類涎显,一個是人,一個是咖啡機(jī)兴猩。

首先是咖啡機(jī)類CoffeeMachine期吓,咖啡機(jī)制作咖啡只需要三個方法:1.加咖啡豆;2.加水倾芝;3.制作咖啡:

@interface CoffeeMachine : NSObject

//加咖啡豆
- (void)addCoffeeBean;

//加水
- (void)addWater;

//制作咖啡
- (void)makeCoffee;

@end

@implementation CoffeeMachine

- (void)addCoffeeBean{
//自行腦補...
}

- (void)addWater{
//自行腦補...
}

- (void)makeCoffee{
//自行腦補...
}

@end

然后就是人類Man讨勤,該類只有一個方法makeCoffee,在該方法中使用咖啡機(jī)制作咖啡:

@interface Man : NSObject

//構(gòu)造方法
- (instancetype)initWithCoffeeMachine:(CoffeeMachine *)coffeeMachine;

//制作咖啡方法
- (void)makeCoffee;

@end

@implementation Man
{
    CoffeeMachine *_coffeeMachine;
}

- (instancetype)initWithCoffeeMachine:(CoffeeMachine *)coffeeMachine{

    self = [super init];
    if (self) {
        _coffeeMachine = coffeeMachine;
    }
    return self;
}

- (void)makeCoffee{
    //使用咖啡機(jī)制作咖啡
    [_coffeeMachine addCoffeeBean];
    [_coffeeMachine addWater];
    [_coffeeMachine makeCoffee];
}

@end

使用場景也非常的簡單:

int main(int argc, const char * argv[]) {

    //創(chuàng)建咖啡對象
    CoffeeMachine *coffeeMachine = [[CoffeeMachine alloc] init];

    //創(chuàng)建人
    Man *man = [[Man alloc] initWithCoffeeMachine:coffeeMachine];

    //人制作咖啡
    [man makeCoffee];

    return 0;
}

在這個例子中晨另,CoffeeMachineMan的直接好友潭千,但問題是ManCoffeeMachine了解的太多了,其實人根本不關(guān)心咖啡機(jī)具體制作咖啡的過程借尿。所以我們可以作如下優(yōu)化:

優(yōu)化后的咖啡機(jī)類刨晴,只暴露一個work方法,把制作咖啡的三個具體的方法addCoffeeBean路翻、addWater狈癞、makeCoffee設(shè)為私有:

@interface CoffeeMachine : NSObject

//只暴露一個方法
- (void)work;

@end

@implementation CoffeeMachine

- (void)work{
        //在work方法中執(zhí)行完整的制作咖啡的過程
    [self addCoffeeBean];
    [self addWater];
    [self makeCoffee];
}

- (void)addCoffeeBean{
//自行腦補...
}

- (void)addWater{
//自行腦補...
}

- (void)makeCoffee{
//自行腦補...
}

@end

現(xiàn)在ManCoffeeMachine的了解只有一個work方法了,所以Man類應(yīng)該修改為:

@interface Man : NSObject

//構(gòu)造方法
- (instancetype)initWithCoffeeMachine:(CoffeeMachine *)coffeeMachine;

//制作咖啡方法
- (void)makeCoffee;

@end

@implementation Man
{
    CoffeeMachine *_coffeeMachine;
}

- (instancetype)initWithCoffeeMachine:(CoffeeMachine *)coffeeMachine{

    self = [super init];
    if (self) {
        _coffeeMachine = coffeeMachine;
    }
    return self;
}

- (void)makeCoffee{
    //使用咖啡機(jī)制作咖啡
    [_coffeeMachine work];
}

@end

這樣修改后茂契,通過減少CoffeeMachine對外暴露的方法蝶桶,減少ManCoffeeMachine的了解,從而降低了它們之間的耦合账嚎。

在實踐中莫瞬,只要做到只和直接的朋友交流減少對朋友的了解,就能滿足迪米特法則郭蕉。因此我們不難想象疼邀,迪米特法則的目的,是把我們的類變成一個個“肥宅”召锈∨哉瘢“肥”在于一個類對外暴露的方法可能很少,但是它內(nèi)部的實現(xiàn)可能非常復(fù)雜(這個解釋有點牽強(qiáng)~)涨岁」胀啵“宅”在于它只和直接的朋友交流。在現(xiàn)實生活中“肥宅”是個貶義詞梢薪,在日本“肥宅”已經(jīng)成為社會問題蹬铺。但是在程序中,一個“肥宅”的類卻是優(yōu)秀類的典范秉撇。

注意

迪米特法則的核心觀念就是類間解耦甜攀,弱耦合秋泄。只有弱耦合了之后,類的復(fù)用才可以提高规阀,類變更的風(fēng)險才可以減低恒序。但解耦是有限度的,除非是計算機(jī)的最小單元--二進(jìn)制的0和1谁撼,否則都是存在耦合的歧胁。所以在實際項目中,需要適度地參考這個原則厉碟,避免過猶不及喊巍。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市墨榄,隨后出現(xiàn)的幾起案子玄糟,更是在濱河造成了極大的恐慌,老刑警劉巖袄秩,帶你破解...
    沈念sama閱讀 219,110評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件阵翎,死亡現(xiàn)場離奇詭異,居然都是意外死亡之剧,警方通過查閱死者的電腦和手機(jī)郭卫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,443評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來背稼,“玉大人贰军,你說我怎么就攤上這事⌒分猓” “怎么了词疼?”我有些...
    開封第一講書人閱讀 165,474評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長帘腹。 經(jīng)常有香客問我贰盗,道長,這世上最難降的妖魔是什么阳欲? 我笑而不...
    開封第一講書人閱讀 58,881評論 1 295
  • 正文 為了忘掉前任舵盈,我火速辦了婚禮,結(jié)果婚禮上球化,老公的妹妹穿的比我還像新娘秽晚。我一直安慰自己,他們只是感情好筒愚,可當(dāng)我...
    茶點故事閱讀 67,902評論 6 392
  • 文/花漫 我一把揭開白布赴蝇。 她就那樣靜靜地躺著,像睡著了一般巢掺。 火紅的嫁衣襯著肌膚如雪句伶。 梳的紋絲不亂的頭發(fā)上芍耘,一...
    開封第一講書人閱讀 51,698評論 1 305
  • 那天,我揣著相機(jī)與錄音熄阻,去河邊找鬼。 笑死倔约,一個胖子當(dāng)著我的面吹牛秃殉,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播浸剩,決...
    沈念sama閱讀 40,418評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼钾军,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了绢要?” 一聲冷哼從身側(cè)響起吏恭,我...
    開封第一講書人閱讀 39,332評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎重罪,沒想到半個月后樱哼,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,796評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡剿配,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,968評論 3 337
  • 正文 我和宋清朗相戀三年搅幅,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片呼胚。...
    茶點故事閱讀 40,110評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡茄唐,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出蝇更,到底是詐尸還是另有隱情沪编,我是刑警寧澤,帶...
    沈念sama閱讀 35,792評論 5 346
  • 正文 年R本政府宣布年扩,位于F島的核電站蚁廓,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏常遂。R本人自食惡果不足惜纳令,卻給世界環(huán)境...
    茶點故事閱讀 41,455評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望克胳。 院中可真熱鬧平绩,春花似錦、人聲如沸漠另。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,003評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽笆搓。三九已至性湿,卻和暖如春纬傲,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背肤频。 一陣腳步聲響...
    開封第一講書人閱讀 33,130評論 1 272
  • 我被黑心中介騙來泰國打工叹括, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人宵荒。 一個月前我還...
    沈念sama閱讀 48,348評論 3 373
  • 正文 我出身青樓汁雷,卻偏偏與公主長得像,于是被迫代替她去往敵國和親报咳。 傳聞我的和親對象是個殘疾皇子侠讯,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,047評論 2 355

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