六大设计原则之三:依赖倒置原则

定义

依赖倒置?大家可能会觉得高深莫测。但是相信听我一翻解说之后,你就会恍然大悟,甚至你早已掌握到它的精髓了。我们先看一下依赖倒置原则的定义:

High level modules should not depend upon low level modules. Both should depend upon abstractions. Abstractions should not depend upon details. Details should depend upon abstractions.(高层模块不应该依赖低层模块,它们都应该依赖其抽象。抽象不应该依赖细节,细节应该依赖抽象。)

意思就是说,无论是高层模块、低层模块还是细节,都应该依赖抽象,所以依赖倒置原则也可以理解为“依赖抽象原则”。那么,什么是依赖呢?假设我们有类A和类B,如果类A需要使用到类B(B是A的属性,或者A会调用到B的方法等),那么可以说类A依赖类B。那么什么又是抽象呢?抽象类、协议都属于抽象。所以,“依赖抽象”就是说当类A用到类B时,尽量引用类B的抽象类或者协议。把依赖倒置原则理解为依赖抽象原则更有助于理解。

大家可能会觉得奇怪,为什么说依赖抽象就是依赖倒置呢?因为在日常生活中,人们习惯于依赖于具体事务(细节),而不是抽象。比如说我们说开车就是具体的车,用电脑就是用具体的电脑。那么如果要倒过来去依赖抽象,就是依赖倒置。

那么为什么要依赖倒置呢?按照人们的直觉依赖正置(依赖具体事务)不好吗?下面就举个依赖正置的例子,来说明依赖正置的问题。

很简单,我们的任务是声明一个司机类和一个奔驰车类,然后让司机开车。我们按照我们现实生活的直觉来,两个类都是具体类,司机就是司机,奔驰车就是奔驰车,没有抽象类的存在。

宝马车类:

@interface BMWCar : NSObject
- (void)run;
@end

@implementation BMWCar
- (void)run{
    NSLog(@"宝马车开动了");
}
@end

司机类:

#import "BMWCar.h"

@interface Driver : NSObject
- (void)driveCar:(BMWCar *)car;
@end

@implementation Driver
- (void)driveCar:(BMWCar *)car{
    [car run];
}
@end

这样就可以让我们的老司机老王开车了:

Driver *wang = [Driver new];
BMWCar *bmw = [BMWCar new];
[wang driveCar:bmw];

上面的代码好像没有什么问题。但是如果现在新增一辆奔驰车,我们的老司机老王却没办法开,因为他目前只有开宝马车的方法!如果要开奔驰车,可能需要为他新增开奔驰车的方法。那么如果现在又要新增特斯拉、奥迪、罗斯莱斯等车呢?难道要为每一辆新增的车去修改司机类?这显然是荒唐的。依赖于具体类,会导致类之间的耦合性太强,这就是在代码中依赖具体类的问题。

虽然说代码是现实世界的反映,但是代码和现实世界还是有所区别的,你需要“倒置”一下。解决上述问题的方法自然是依赖倒置,让司机依赖于抽象的车,而不是具体的车。

抽象车类:

@interface Car : NSObject
- (void)run;
@end

@implementation Car
- (void)run{
}
@end

司机类(记得司机类现在依赖的是抽象的车类,而不是具体的车类):

#import "Car.h"

@interface Driver : NSObject
- (void)driveCar:(Car *)car;
@end

@implementation Driver
- (void)driveCar:(Car *)car{
    [car run];
}
@end

然后,就是我们的具体车类了。只要具体的车类继承自抽象车类,那么无论它是奔驰车,还是宝马车...我们的司机都可以开。

奔驰车:

@interface BenzCar : Car
@end

@implementation BenzCar
- (void)run{
    NSLog(@"奔驰车开动了");
}
@end

让我们的老王开开奔驰:

Driver *wang = [Driver new];
Car *benz = [BenzCar new];
[wang driveCar:benz];

宝马车:

@interface BMWCar : Car
@end

@implementation BenzCar
- (void)run{
    NSLog(@"宝马车开动了");
}
@end

让我们的老王也开开宝马:

Driver *wang = [Driver new];
Car *bmw = [BMWCar new];
[wang driveCar:bmw];

可见通过依赖倒置,现在无论新增多少种车,都不需要去修改司机类了。

优点

通过上面的例子,相信大家已经领略到在代码中使用依赖倒置原则的重要性了。总结一下依赖倒置原则的优点:

  1. 减少类之间的耦合;
  2. 降低并行开发引起的风险;
  3. 提高代码的可读性和可维护性。

关于上面第2点需要强调一下,依赖倒置对于并行开发非常重要,可以说是必不可少。因为在多个人一起进行开发的时候,如果没有抽象类或者接口,你要等到别人完成具体的类才能进行开发,那么谈何并行开发?相反我们只需要先定好抽象类或者接口,大家就能开工了。所以在并行开发的时候一定要遵守依赖倒置原则。

实践

到这里相信大家已经知道依赖倒置原则是怎么回事了。也许这你是第一次听说依赖倒置原则,但是你很可能听说过面向接口编程。面向接口编程是依赖倒置原则的最佳实践,如果你熟悉面向接口编程,那么恭喜你已经掌握了依赖倒置原则的精髓。

如果还是觉得抽象,下面列举一些具体的点,让大家可以有法可依:

  1. 每个类尽量都有接口或抽象类,或者两者具备。抽象是依赖倒置原则的基本要求;
  2. 变量的表面类型尽量是接口或者抽象类;
  3. 任何类都尽量不要从具体类派生。如果一个类是从具体类派生,那么这个类和它的非抽象的父类就形成强耦合;
  4. 尽量不要覆写基类的方法。如果基类是一个抽象类,而且这个方法已经实现了,子类尽量不要覆写。类间的依赖是抽象,覆写了抽象方法,会影响依赖的稳定性;
  5. 结合里氏替换原则使用。

注意

  1. 依赖倒置原则的优点很难在小项目中体现出来,在大型项目才能感受到它的重要性;
  2. 依赖倒置原则是6大设计原则中最难实现的;
  3. 有些情况还是需要依赖于细节。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,335评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,895评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,766评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,918评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,042评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,169评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,219评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,976评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,393评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,711评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,876评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,562评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,193评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,903评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,142评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,699评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,764评论 2 351

推荐阅读更多精彩内容