设计模式原则之单一职责原则

定义

There should never be more than one reason for a class to change.

应该有且仅有一个原因引起类的变更。


优点

降低类的复杂性

每个类实现单一职责,并且单一职责都有清楚明确的定义,复杂性当然降低。

提高可读性 

类的复杂性降低了,当然提高了可读性了。

提高可维护性 

类的复杂性降低,可读性好,当然好维护。

易于测试

测试单一目标的类只需要很少的测试类。让“用测试替代文档” “self documentation by tests”变得更加容易

易于调试

在一个单一职责类找到问题是一件更容易的事情。


变更引起的风险降低,变更是必不可少的,如果接口的单一职责做的好,一个接口修改只对相应的实现类有影响,对其它的接口没有影响,这对系统的扩展性,维护性都是有好处的。


类的单一职责原则

一般一个对象可以分为属性行为二部分,所以在类的设计时,我们一般把对象的属性抽象成一个BO(Business Object,业务对象),把对象的行为抽象成一个Biz(Business Logic,业务逻辑)


产生原因

没有任何的程序设计人员不清楚应该写出高内聚低耦合的程序,但是很多耦合常常发生在不经意之间,其原因就是:职责扩散:因为某种原因,某一职责被分化为颗粒度更细的多个职责了

解决办法

遵守单一职责原则,将不同的职责封装到不同的类或模块中。


场景模拟

我们需要创作一个论坛,需要发布主题和回帖功能

场景模拟UML 图


场景模拟UML图

简单代码

@protocol Thread<NSObject>

-(void)addReplayMessage;

@end

#import "Thread.h"

@protocol Forum<NSObject>

-(void)addThread:(id<Thread>)thread;

-(void)addReplayMessage;

@end

#import "Forum.h"

@interface ForumObject : NSObject<Forum>

@end

#import "ForumObject.h"

@interface ForumObject()

@property (nonatomic,strong) id<Thread>thread;

@end@implementation ForumObject

-(void)addThread:(id<Thread>)thread{

    self.thread = thread;

}

-(void)addReplayMessage{

    [self.thread addReplayMessage];

}

@end

#import "Thread.h"

@interface ThreadObject : NSObject<Thread>

@property (nonatomic,strong) NSString *name;

@end

#import "ThreadObject.h"

@implementation ThreadObject

-(void)addReplayMessage{

    NSLog(@"%@ 回复信息",self.name);

}

@end


测试代码

id<Forum> forumObject = [ForumObject new];

ThreadObject * threadobject = [ThreadObject new];

threadobject.name =@"单一职责原则";

[forumObject addThread:threadobject];

[forumObject addReplayMessage];

测试结果

2018-04-04 14:39:55.425610+0800 设计模式原则[90446:6274362] 单一职责原则 回复信息


分析

我们都知道一个论坛的结构一般是

forum------->Thread----------->Message

一个论坛Forum中有多个Thread ,一个Thread 有多个回帖和跟帖。

根据这个层次结构,forum 增加回帖的功能有点太宽了,这个功能应该属于Thread的


代码重构

#import "Thread.h"

@protocol ForumNew<NSObject>

-(void)addThread:(id<NSObject>)thread;

@end

#import "ForumNew.h"

@interface ForumNewObject : NSObject<ForumNew>

@end

#import "ForumNewObject.h"

@interface ForumNewObject()

@property (nonatomic,strong) id<Thread>thread;

@end

@implementation ForumNewObject-

(void)addThread:(id<Thread>)thread{

    self.thread = thread;

}

@end

测试代码

 id<ForumNew> forumObject= [ForumNewObject new];

   ThreadObject * threadobject = [ThreadObject new];

    threadobject.name =@"单一职责原则";

    [forumObject addThread:threadobject];

    [threadobject addReplayMessage];

结果

2018-04-04 14:50:13.955267+0800 设计模式原则[93059:6286368] 单一职责原则 回复信息

其实重构代码就是讲回帖的功能从forum拿到了Thread中,代码很简单,就是需要体会下。

上述问题产生的原因是因为当时我们把论坛的Thread和Message都当做论坛的一个功能。由于后期业务变更,导致Thread  和Message 需要划分为更细致。


如何识别SRP被破坏?

类有太多依赖

类的构造器有太多参数,意味着测试有太多依赖,需要制造mock太多测试输入参数,通常意味着已经破坏SRP了。

方法有太多参数

类似类的构造器,方法参数意味着依赖。

测试类变得复杂

如果测试有太多变量,意味着这个类有太多职责。

类或方法太长

如果方法太长,意味着内容太多,职责过多。

一个类不超过 200-250

描述性名称

如果你需要描述你的类 方法或包,比如使用"xxx和xxx"这种语句,意味着可能破坏了SRP.

低聚合Cohesion的类

聚合Cohesion是一个很重要的概念,虽然聚合是有关结构概念,但是聚合和SRP非常相关,如前面论坛案例,如果一个类不代表一个高聚合,意味着低凝聚low Cohesion,它就可能意味破坏SRP。一个低凝聚的特点:

一个类有两个字段,其中一个字段被一些方法使用;另外一个字段被其他方法使用。

在一个地方改动影响另外一个地方

如果在一个代码地方加入新功能或只是简单重构,却影响了其他不相关的地方,意味着这个地方代码可能破坏了SRP.

猎枪效果Shotgun Effect

如果一个小的改变引起一发动全身,这意味SRP被破坏了。

不能够封装模块

比如使用Spring框架,你使用@Configuration or XML 配置,如果你不能在一个配置中封装一个Bean。意味着它有太多职责,Spring配置应该隐藏内部bean,暴露最少接口,如果你因为多个原因需要改变Spring配置,可能破坏了SRP.


借鉴博客

单一职责原则(SRP)

六大设计原则之单一职责原则

源代码地址

下一篇博客

设计原则之迪米特原则

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

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,646评论 18 139
  • 转至元数据结尾创建: 董潇伟,最新修改于: 十二月 23, 2016 转至元数据起始第一章:isa和Class一....
    40c0490e5268阅读 1,698评论 0 9
  • 定义 The dependency of one class to another one should depe...
    充满活力的早晨阅读 486评论 0 1
  • 这个世界有多美好,这个世界就有多糟糕。
    凌凌魕阅读 179评论 0 0
  • “春游去喽!”同学们像一群快乐的小鸟,在老师的带领下兴高采烈的上了大巴车。 在大巴车上,我们认识了周...
    2e45075fd084阅读 293评论 2 0