聊聊设计模式原则(一) -- 单一职责原则

目录

单一职责原则(SRP:Single responsibility principle)

定义

一个类应该只有一个发生变化的原因,即一个类只负责一项职责。
如果一个类有多个职责,这些职责就耦合在了一起。当一个职责发生变化时,可能会影响其它的职责。另外,多个职责耦合在一起会影响复用性。
此原则的核心是解耦和增强内聚性。

由来

类A负责两个职责:职责P1,职责P2。当由于职责P1需求发生改变而需要修改类A时,有可能会导致原本运行正常的职责P2功能发生故障。

解决方案

遵循SRP。分别建立两个类A1、A2,使A1完成职责P1,A2完成职责P2。这样,当修改类A1时,不会影响到职责A2;同理,当修改A2时,也不会影响到职责P1。

优点

降低类的复杂度,一个类只负责一项职责,其逻辑肯定要比负责多项职责简单的多。
提高类的可读性,提高系统的可维护性。
变更引起的风险降低,变更是必然的,如果SRP遵守的好,当修改一个功能时,可以显著降低对其他功能的影响。

e.g.

iOS开发中,SRP最好的反例的应该就是 Massive View Controller。比如随便写一个简单的应用程序,一般都会生成一个ViewController类,于是我们将各种各样的代码,算法、网络请求、数据库访问等等都放在这个类里面,这就意味着,无论任何需求变化,都要来修改ViewController这个类,这其实是很糟糕的,维护麻烦、复用不可能、缺乏灵活性等。关于这点网上也有很多解决方法:8 种模式帮你告别 Massive View Controller,但无论什么方法,都是在提倡优化职责划分,也就是SRP的思想。

曾几何时我们很自然地将Model传给Cell,然后让Cell解析Model去渲染视图,并且感觉没有什么不妥,美其曰“Cell的封装”。代码如下:

TestCell *cell = [tableView dequeueReusableCellWithIdentifier:@"TestCell"];
if (!cell) {
        cell = (TestCell *)[[[NSBundle mainBundle] loadNibNamed:@"TestCell" owner:self options:nil] lastObject];
}
TestModel *model = self.dataList[indexPath.row];
[cell configWithModel:model];

殊不知这已经违背了SRP,Cell的职责是描述与渲染自身,解析Model这个职责不属于Cell,并且在Cell中引入Model会增加不必要的依赖,Cell需要根据Model的改变而做出相应的修改,不利于Cell的复用。做过Android开发的同学知道,其实如何让Model的数据呈现在Cell上是Adapter需要做的事情。

一些看法

用一个场景来描绘下。
用一个类描述程序员写代码

@implementation Programmer
-(Void) program:(NSString* name){
    NSLog(@"%@写OC代码",name);
}
@end

//Client
Programmer* programmer = [[Programmer alloc]init];
[programmer program:@"iOS工程师"];

//Result
“iOS工程师写OC代码”

殊不知,iOS只是代码界的一部分

[programmer program:@"前端工程师"];

//Result
“前端工程师写OC代码”

发现不对劲了,这个时候想到了SRP,要不这样改改

@implementation IOSProgrammer
-(Void) program:(NSString* name){
    NSLog(@"%@写OC代码",name);
}
@end

@implementation WebProgrammer
-(Void) program:(NSString* name){
    NSLog(@"%@写JS代码",name);
}
@end

//Client
IOSProgrammer* iOSprogrammer = [[IOSProgrammer alloc]init];
[iOSprogrammer program:@"iOS工程师"];
WebProgrammer* webProgrammer = [[WebProgrammer alloc]init];
[webProgrammer program:@"前端工程师"];

//Result
“iOS工程师写OC代码”
“前端工程师写JS代码”

我们会发现如果这样修改花销是很大的,除了将原来的类分解之外,还需要修改客户端。而直接修改类Programmer来达成目的虽然违背了SRP但花销却小的多,代码如下:

@implementation Programmer
-(Void) program:(NSString* name){
    if([name isEqualToString:@"iOS工程师"]){
        NSLog(@"%@写OC代码",name);
    }else  if([name isEqualToString:@"前端工程师"]){
        NSLog(@"%@写JS代码",name);
    }
}
@end

可以看到,这种修改方式要简单的多。但是却存在着隐患:有一天需要后台程序员写PHP,则又需要修改Programmer类的program方法,而对原有代码的修改会对调用iOS工程师、前端工程师带来风险。这种修改方式直接在代码级别上违背了SRP,虽然修改起来最简单,但隐患却是最大。
那么还有别的方式吗?答案是肯定的,代码如下:

@implementation Programmer
-(Void) program:(NSString* name){
    NSLog(@"%@写OC代码",name);
}

-(Void) program2:(NSString* name){
    NSLog(@"%@写JS代码",name);
}
@end

//Client
Programmer* programmer = [[Programmer alloc]init];
[programmer program:@"iOS工程师"];
Programmer* programmer2 = [[Programmer alloc]init];
[programmer2 program2:@"前端工程师"];

//Result
“iOS工程师写OC代码”
“前端工程师写JS代码”

这种在类中新加一个方法的修改方式,虽然也违背了SRP,但在方法级别上却是符合SRP的,因为它并没有动原来方法的代码。
这三种方式各有优缺点,在开发中,需要根据实际情况来确定。需要注意的是:只有逻辑足够简单,才可以在代码级别上违反SRP;只有类中方法数量足够少,才可以在方法级别上违反SRP;

很多人对SRP不屑一顾,因为它太简单了。但即便是经验丰富的程序员写出的程序,也会有违背这一原则的代码存在。其原因是因为有职责扩散。所谓职责扩散,就是因为某种原因,职责P被分化为粒度更细的职责P1和P2。需要注意的是:在职责扩散到我们无法控制的程度之前,要立刻对代码进行重构。

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

推荐阅读更多精彩内容