深一层看单一职责原则

单一职责原则(Single Responsibility Principle, SRP)是Bob大叔提倡的S.O.L.I.D五大 设计原则中的第一个。其中,职责(Responsibility)被表述为“变化的原因” (reason to change);SRP被表述为“一个类应该有且只有一个变化的原因”。但如果光从字面去理解, SRP很容易让人望文生义产生误解。本文希望能阐明SRP 的本质,达到避免误解和指导设计的 目的。

动机

对于设计原则的理解应该首先从它的动机入手,即遵循这个原则带来的好处是什么?对于 SRP来讲,如果遵循“一个类应该有且只有一个变化的原因”是因,那么“任何一个变化只会 影响一个类”就是果。可见SRP的动机主要是系统的可维护性,即降低适应变化的成本。

多功能与单变化

对于单功能的类来讲,比较容易遵循SRP,比如:把string转换为DateTime类型的工具类 。理解SRP的难点在于在多功能类的情形,即不容易理解多功能与单变化的矛盾。让我们先来 看一个Modem类的例子,Modem具有4个功能:拨号,挂断,发送数据,接收数据:

class Modem {
     public void Dial(string aPno) {…}
     public void Hangup() {…}
     public void Send(char aData) {…}
     public char Receive() {…}
}

我们先来考察一下Modem类的变化点,并将其分为两类:1.Modem类的内部细节变化,比如 Dial、Hangup、Send、Receive等具体实现发生了变化;2.Modem类整体性的变化,比如Modem 类需要增加Poweron和Poweroff方法。上面的Modem类具有多个变化点,不符合SRP。

抽象与抽象层次

但是,需要注意的是上面的Modem类其实是很符合现实的概念模型的,Modem本身就应该具 有这几个功能点。难道要把Modem类强行拆开吗,难道所有类都只应该有一个方法吗?是什么 原因导致符合现实概念模型的Modem类设计与SRP不符合呢?问题在于抽象与抽象层次,Modem 类是现实概念模型的抽象没有错,但是Modem类缺乏抽象层次,低层概念与高层概念混杂,这 正是问题所在。下面是重构以后的Modem类:

interface IDialable{
     void Dial(string aPno);
}
class Dialer : IDialable{
     public void Dial(string aPno){…}
}

class Modem{
     public void Dial(string aPno) { m_dialer.Dial(aPno); }
     private IDialable m_dialer;

     … //hangup, send, receive类似
}

上面的设计将各个功能点抽象为单一的接口,将变化封装在稳定的接口背后,再通过组合 的方式建立起整体的Modem类与局部的功能点的联系。这样就避免了低层的变化传导到高层。

总结

可见,理解SRP的关键在于理解类的抽象层次,高层次的类是高层概念的抽象,低层次的 类是低层概念的抽象。低层的变化只影响低层类,高层的变化只影响高层类。对于遵守SRP的 设计,一定具有很好的抽象层次,因此不妨以SRP为指导和检验,帮助我们设计出好的类来。 最后,我用几个关键词梳理SRP的脉络:

类只有一个变化的原因 >> 一个变化只影响一个类 >> 变化只影响其相应层 次的类

时间: 2024-07-31 08:03:59

深一层看单一职责原则的相关文章

《你必须知道的.net》读书笔记 006——2.2 单一职责原则

       单一职责原则,核心思想:一个类最好只做一件事情,只有一个引起她变化的原因.        就是分工合作的意思.一个人只做一种事情,比如设计师负责设计页面,做出来PS图,美工负责把PS图片,切成HTML代码的形式,加上css效果.flash动画等,程序员负责加代码.而程序员这里又可以细分一下,有的负责UI,有的负责业务逻辑,有的负责数据操作,对了还有架构师.技术经理.项目经理等.最后还要有专门负责测试的人员.        其实上面有点扯淡的味道,往往小公司是做不到这些的.还是说程序

单一职责原则

单一职责原则 单一职责原则(Simple responsibility pinciple SRP) 就一个类而言,应该仅有一个引起它变化的原因,如果你能想到多于一个的动机去改变一个类,那么这个类就具有多于一个的职责.应该把多于的指责分离出去,分别再创建一些类来完成每一个职责. 单一职责原则是软件设计7大原则之一,其核心思想就是最大限度的提升代码的可复用性.   以下以具体的例子阐述,为何单一职责原则能最大限度的提升代码的可复用性. 之前写过一篇教程,教大家通过runtime扩展了NSObject

【转载】设计模式六大原则(1):单一职责原则

定义:不要存在多于一个导致类变更的原因.通俗的说,即一个类只负责一项职责. 问题由来:类T负责两个不同的职责:职责P1,职责P2.当由于职责P1需求发生改变而需要修改类T时,有可能会导致原本运行正常的职责P2功能发生故障. 解决方案:遵循单一职责原则.分别建立两个类T1.T2,使T1完成职责P1功能,T2完成职责P2功能.这样,当修改类T1时,不会使职责P2发生故障风险:同理,当修改T2时,也不会使职责P1发生故障风险.          说到单一职责原则,很多人都会不屑一顾.因为它太简单了.稍

设计模式六大原则(1):单一职责原则

定义:不要存在多于一个导致类变更的原因.通俗的说,即一个类只负责一项职责. 问题由来:类T负责两个不同的职责:职责P1,职责P2.当由于职责P1需求发生改变而需要修改类T时,有可能会导致原本运行正常的职责P2功能发生故障. 解决方案:遵循单一职责原则.分别建立两个类T1.T2,使T1完成职责P1功能,T2完成职责P2功能.这样,当修改类T1时,不会使职责P2发生故障风险:同理,当修改T2时,也不会使职责P1发生故障风险.          说到单一职责原则,很多人都会不屑一顾.因为它太简单了.稍

设计模式六大原则 单一职责原则

设计模式六大原则(1):单一职责原则 定义:不要存在多于一个导致类变更的原因.通俗的说,即一个类只负责一项职责,一个人只负责做一件事. ( 一个类,只有一个引起它变化的原因.应该只有一个职责.每一个职责都是变化的一个轴线,如果一个类有一个以上的职责,这些职责就耦合在了一起.这会导致脆弱的设计.当一个职责发生变化时,可能会影响其它的职责.另外,多个职责耦合在一起,会影响复用性.例如:要实现逻辑和界面的分离 ) 问题由来:类T负责两个不同的职责:职责P1,职责P2.当由于职责P1需求发生改变而需要修

设计模式六大原则——单一职责原则(SRP)

      定义       就一个类而言,应该仅有一个引起它变化的原因.通俗的说,一个类只负责一项职责.       问题的由来       手机的功能多,但是每一项的功能都不强:       拍摄功能-->专业的摄像机和照相机       手机游戏-->PSP       网络摄像头-->专业摄像头       GPS功能-->专业GPS导航系统       每一个职责都是一个变化的轴线,当需求变化时会反映为类的职责的变化,如果一个类的承担的职责多于一个,那么引起她变化的原因就

简单讲解Java设计模式编程中的单一职责原则_java

单一职责原则:一个类,只有一个引起它变化的原因. 为什么需要单一职责原则? 如果一个类有多个原因要去修改它,那么修改一个功能时,可能会让其他功能产生Bug,所以一个类最好只有一个职责.但实际应用中还是比较难实现的,我们只能是尽量符合这个原则. 有时候,开发人员设计接口的时候会有些问题,比如用户的属性和用户的行为被放在一个接口中声明.这就造成了业务对象和业务逻辑被放在了一起,这样就造成了这个接口有两种职责,接口职责不明确,按照SRP的定义就违背了接口的单一职责原则了. 下面是个例子: packag

《Android 源码设计模式解析与实战》——第1章,第1.1节优化代码的第一步——单一职责原则

第1章 走向灵活软件之路--面向对象的六大原则Android 源码设计模式解析与实战 1.1 优化代码的第一步--单一职责原则单一职责原则的英文名称是Single Responsibility Principle,缩写是SRP.SRP的定义是:就一个类而言,应该仅有一个引起它变化的原因.简单来说,一个类中应该是一组相关性很高的函数.数据的封装.就像老师在<设计模式之禅>中说的:"这是一个备受争议却又及其重要的原则.只要你想和别人争执.怄气或者是吵架,这个原则是屡试不爽的".

函数的单一职责原则(SRP)

结构化编程强调单一出口的原则,其目的在于增强函数流程的逻辑性.本身这个原则有些过于死板,但其保持代码逻辑性的目的是非常正确的.在面向对象设计,我们都知道要遵循单一职责原则(SRP),而函数也应遵循这一原则,以保证函数体逻辑的清晰并且高内聚.   以下示例中,UpdateValue函数与下面m_value的赋值语句造成了逻辑的分散: 当需要变更m_value的赋值逻辑时,往往会修改UpdateValue函数,而忽略了下面的赋值语句,这就会引起新的问题.顾此失彼嘛!   这种情况在代码维护时最容易引