我知道"班级有一个改变的理由".现在,到底是什么?是否有一些气味/迹象可以说明该课程没有一个责任?或者,真正的答案是否可以隐藏在YAGNI中,并且只有在您的班级第一次更改时才重构一项责任?
有许多明显的情况,例如CoffeeAndSoupFactory
.同一装置中的咖啡和汤会导致非常令人不快的结果.在此示例中,设备可能会被分解为HotWaterGenerator
某种类型Stirrer
.然后可以从这些组件构建新的CoffeeFactory
并且SoupFactory
可以避免任何意外混合.
在更微妙的情况中,数据访问对象(DAO)和数据传输对象(DTO)之间的紧张关系非常普遍.DAO与数据库通信,DTO可序列化,以便在进程和机器之间进行传输.通常DAO需要对数据库框架的引用,因此它们在富客户端上不可用,它们既没有安装数据库驱动程序,也没有访问数据库所需的权限.
类中的方法开始按功能区域分组("这些是Coffee
方法,这些是Soup
方法").
实现许多接口.
写一个简短但准确的描述课程的内容.
如果描述中包含单词"and",则需要将其拆分.
嗯,这个原则是用一些盐...以避免类爆炸.
单个责任不会转换为单个方法类.它意味着存在的一个原因......对象为其客户提供的服务.
留在路上的好方法...使用对象作为人物隐喻...如果对象是一个人,我会要求他做谁?将该责任分配给相应的类.但是,您不会要求同一个人执行您的管理文件,计算工资,发放薪水和验证财务记录......为什么您希望单个对象执行所有这些操作?(如果一个班级承担多重责任,只要它们都是相关且连贯的,那就没关系.)
如果您使用CRC卡,这是一个很好的细微指南.如果你无法在CRC卡上获得该对象的所有责任,那么它可能做得太多了......最多7个就可以作为一个好的标记.
重构书中的另一个代码味道是巨大的类.霰弹枪手术将是另一个......改变班级中的一个区域会导致同一级别的无关区域出现错误......
发现你一次又一次地对同一个类进行无关错误修复的更改是另一个迹象表明该类做得太多了.
一种简单实用的方法来检查单一责任(不仅是类而且还有类的方法)是名称选择.当您设计一个类时,如果您轻松找到该类的名称,该名称确切地指定了它所定义的内容,那么您的方法就是正确的.选择名称的困难几乎总是设计糟糕的症状.
你的类中的方法应该是有凝聚力的...它们应该协同工作并在内部使用相同的数据结构.如果你发现你有太多的方法似乎没有完全相关,或者似乎在不同的事情上运作,那么你很可能没有一个好的单一责任.
通常很难找到责任,有时你需要在几个不同的上下文中使用该类,然后在开始看到区别时将类重构为两个类.有时您会发现这是因为您将抽象的具体概念混合在一起.它们往往更难以看到,而且,在不同的背景下使用将有助于澄清.
显而易见的迹象是,当你的班级最终看起来像一个泥球大球时,这实际上与SRP(单一责任原则)相反.
基本上,所有对象的服务应该集中在执行单一职责上,这意味着每当你的课程改变并添加一个不尊重它的服务时,你就知道你正在"偏离""正确"的路径;)
原因通常是由于一些快速修复,匆忙添加到类中修复一些缺陷.因此,您更改课程的原因通常是检测您是否要打破SRP的最佳标准.