一、定义

  一个类应该只有一个发生变化的原因。

二、为什么要使用SRC

  因为每一个职责都是变化的一个轴线。当需求变化时,这种变化就会反映为类的职责的变化。如果一个类承担了多于一个的职责,那么引起它变化的原因就会有多个。

  如果一个类承担的职责过多,就等于把这些职责耦合在了一起。一个职责的变化可能会消弱或抑制这个类完成其他职责的能力。这种耦合会导致脆弱的设计,当变化发生时,设计会遭到意想不到的破坏。

三、案例演示

  考虑图中的设计。

  

  Rectangle类具有两个方法,一个方法把矩形绘制到屏幕上,另一个方法则是计算矩形的面积。 现在有两个应用程序使用Rectangle类。一个是利用Rectangle计算矩形面积,但不需要绘制矩形;另一个应用程序可能会绘制矩形,也可能计算面积。

  这个设计违反了单一职责原则。Rectangle类具有两个职责。第一个职责提供了矩形面积的计算;第二个职责提供了矩形绘制。 对于SRC的违反导致了一些严重的问题。

  对于这个违反了SRC的程序有以下几点问题:

  首先,我们必须在左侧的程序中包含进GUI代码,即使我们是不需要的。

  其次,如果右侧程序的改变导致了Rectangle的改变,那么这个改变会迫使我们重新构建、测试和部署左侧的程序。

   一个较好的设计就是把这两个职责分离到如下图所示的两个完全不同的类中。这个设计把Rectangle类中进行计算的部分移到了GeometricRectangle类中。现在矩形绘制方法的变化不会影响到左侧的程序。

  

四、什么是职责

  在SRC中,我们把职责定义为变化的原因

  如果你能够想到多于一个的动机去改变一个类,那么这个类就具有多于一个的职责。

  有时,我们很难注意到这一点,我们习惯于以组的形式去考虑职责。 例如,下面的Modem接口,大多数人认为这个接口非常合理。该接口所声明的4个方法确实是调制解调器所具有的功能 。

public interface Modem
{
public void Dial(string pno); //连接
public void Hangup(); //断开
public void Send(char c); //发送
public char Recv(); //接收
}

  然而,该接口中却显示出两个职责。第一个职责是连接管理;第二个职责是数据通信。

  这两个职责需要分开吗?

  这依赖于应用程序变化的方式。如果应用程序的变化会影响到连接管理方法的签名,那么这个设计就具有僵化性,因为调用send和recv的类必须重新编译、部署。在这种情况下,这两个职责应该被分离,如下图所示。

  

  另一方面,如果应用程序的变化方式总是导致这两个职责同时变化,那就不必分离它们。

  记住这么一个结论,仅当变化发生时,变化的轴线才具有实际意义。如果没有征兆,那么应用SRP或者任何其它原则都是不明智的。

五、分离耦合的职责

  请注意,在上图中,把两个职责都耦合进了ModemImplementation类中。这也许不是最好的,但是或许必须得这么做。常常会有一些和硬件或者操作系统的细节有关的原因,迫使我们把不愿意耦合在一起的东西耦合在了一起。然而,对于应用的其余部分来说,通过分离它们的接口我们已经解耦了。

六、持久化

  下图展示了一种常见的违反SRP的情形。

  

  Employee类包含了业务规则和对于持久化的控制。这个两个职责在大多数情况下绝不应该混合在一起。业务规则往往会频繁地变化,而持久化的方式却不会如此频繁的变化,并且变化的原因也是完全不同的,它们实在两个方向上变化,一个是业务方向上变化,另一个是持久化方向上变化。

  把业务规则和持久化子系统绑定在一起的做法是自讨苦吃。 测试驱动的开发实践常常会远在设计出现臭味之前就迫使我们分离这两个职责。然而,如果测试没有迫使这种分离,那么就应该使用Facade(外观)、DAO(数据访问)或者Proxy(代理)模式对设计进行重构,分离这两个职责。

七、结论

  SRP是所有原则中最简单的原则之一,也是最难正确运用的原则之一。我们会不自觉地把职责结合到一起。软件设计真正要做的许多工作,就是发现职责并把那些职责相互分离。

SRC单一职责原则的更多相关文章

  1. C#设计模式系列:单一职责原则(Single Responsibility Principle)

    1.单一职责原则的核心思想 一个类应该有且只有一个变化的原因. 2.为什么要引入单一职责原则 单一职责原则将不同的职责分离到单独的类,每一个职责都是一个变化的中心.当需求变化时,这个变化将通过更改职责 ...

  2. C#软件设计——小话设计模式原则之:单一职责原则SRP

    前言:上篇C#软件设计——小话设计模式原则之:依赖倒置原则DIP简单介绍了下依赖倒置的由来以及使用,中间插了两篇WebApi的文章,这篇还是回归正题,继续来写写设计模式另一个重要的原则:单一职责原则. ...

  3. 单一职责原则(Single Responsibility Principle)

    单一职责原则(SRP:The Single Responsibility Principle) 一个类应该有且只有一个变化的原因. There should never be more than on ...

  4. 开放-封闭原则(OCP)开-闭原则 和 依赖倒转原则,单一职责原则

    单一职责原则 1.单一职责原则(SRP),就一个类而言,应该仅有一个引起它变化的原因 2.如果一个类承担的职责过多,就等于把这些职责耦合在一起,一个职责的变化可能会消弱或抑制这个类完成其他职责的能力. ...

  5. 敏捷软件开发:原则、模式与实践——第8章 SRP:单一职责原则

    第8章 SRP:单一职责原则 一个类应该只有一个发生变化的原因. 8.1 定义职责 在SRP中我们把职责定义为变化的原因.如果你想到多于一个的动机去改变一个类,那么这个类就具有多于一个的职责.同时,我 ...

  6. 第2章 面向对象的设计原则(SOLID):1_单一职责原则(SRP)

    1. 单一职责原则(Single Responsibility Principle,SRP) 1.1 单一职责的定义 (1)定义:一个类应该仅有一个引起它变化的原因.这里变化的原因就是所说的“职责”. ...

  7. 1.单一职责原则(Single Responsibility Principle)

    1.定义 就一个类而言,应该仅有一个引起它变化的原因. 2.定义解读 这是六大原则中最简单的一种,通俗点说,就是不存在多个原因使得一个类发生变化,也就是一个类只负责一种职责的工作. 3.优点 类的复杂 ...

  8. 【设计模式六大原则1】单一职责原则(Single Responsibility Principle)

        http://blog.csdn.net/zhengzhb/article/category/926691/1 图片素材来源,java学习手册 ps.内容为自己整理   定义:不要存在多于一个 ...

  9. [设计模式]<<设计模式之禅>>之关于单一职责原则

    单一职责原则的英文名称是Single Responsibility Principle,简称是SRP. 这个原则存在争议之处在哪里呢?就是对职责的定义,什么是类的职责,以及怎么划分类的职责.我们先举个 ...

随机推荐

  1. 像素图的实时光照 Lighting on Pixel Art

    去年有这样一个工具,We got one toolkit last year. 他有什么功能呢?What is its function? 让你画出各个方向的照明图 That you can draw ...

  2. Chrome扩展程序的二次开发:把它改得更适合自己使用

    我当然知道未经作者允许修改别人程序是不道德的了,但作为学习研究之用还是无可厚非,这里仅供交流. 一切都是需求驱动的 话说某天我在网上猎奇的时候无意间发现这么一款神奇的谷歌浏览器插件:Extension ...

  3. 翻译-高效DevOps的10项实践

    原文链接: http://www.drdobbs.com/architecture-and-design/top-10-practices-for-effective-devops/240149363 ...

  4. ActiveMQ第六弹:设置多个并行的消费者

    消息队列本来就是一种经典的生产者与消费者模式.生产者向消息队列中发送消息,消费者从消息队列中获取消息来消费. 消息的传送一般由一个代理来实现的,那就是Message broker(即消息代理).Mes ...

  5. WebApi系列~在WebApi中实现Cors访问

    回到目录 说在前 Cors是个比较热的技术,这在蒋金楠的博客里也有体现,Cors简单来说就是“跨域资源访问”的意思,这种访问我们指的是Ajax实现的异步访问,形象点说就是,一个A网站公开一些接口方法, ...

  6. EF架构~XMLRepository仓储的实现

    回到目录 对于数据仓储大家应该都很熟悉了,它一般由几个仓储规范和实现它的具体类组成,而仓储的接口与架构本身无关,对于仓储的实现,你可以选择linq2Sql,EF,Nosql,及XML 等等,之前我介绍 ...

  7. Java的String字符串内容总结

    String--字符串 获取字符串的长度 使用Sring类的length()方法可获取字符串对象的长度,例: str.length(); str代表指定的字符串对象;返回值为返回指定字符串的长度.例: ...

  8. salesforce 零基础学习(十七)Trigger用法

    看本篇之前可以相应阅读以下Trigger相关文章: 1.https://developer.salesforce.com/page/Trigger_Frameworks_and_Apex_Trigge ...

  9. js在控件原有的事件方法中加入自己的方法

    有没有碰到过这样的情况,在一个别人的页面上,你想为某个按钮加入自己的控制逻辑,满足条件的情况下才执行原有的事件方法呢? 这个时候在不能修改其原有方法的情况下,先获取控件的事件方法,并将其包装到自己的控 ...

  10. WPF自定义控件与样式(12)-缩略图ThumbnailImage /gif动画图/图片列表

    一.前言 申明:WPF自定义控件与样式是一个系列文章,前后是有些关联的,但大多是按照由简到繁的顺序逐步发布的等,若有不明白的地方可以参考本系列前面的文章,文末附有部分文章链接. 本文主要针对WPF项目 ...