我需要帮助澄清我对单一责任原则(SRP)的理解(错误)。
在我参与的许多项目中,我的同事认为SRP意味着一个类应该实现非常有限的功能,例如计算一组对象的总计。这导致具有一种公共方法(一种责任)的类,例如, CalculateTotals(...)
。我不是DDD专家,但从我所看到的这导致了贫血领域模型,DTO和无休止的微服务。
采用这种方法并在混合中添加DRY会导致在应用程序的不同部分重用这些类。
我倾向于将SRP视为更高层次的需求水平。例如,需要计算总计数以用于报告与需要计算税务相关计算的总计。在这种情况下应用DRY可能会导致意外错误。当总计算逻辑由于报告要求的变化而需要改变时,如果我们已经应用DRY并重新使用该类,我们将打破我们的税收计算。
鉴于改变的原因只是由于需求的变化(我不认为在这里适用重新分解),DRY原则应仅限于一个用例吗?
如果上述陈述是正确的,是否意味着我们不必将税收计算分解为单独的类别?好吧,我们可以这样做来简化代码,但是我们不会因为SRP原因而这样做吗?
我的思考错了吗?
答案 0 :(得分:4)
单一责任原则实际上是什么意思?
The Single Responsibility Principle doesn't say that a class should implement very limited functionality, it says that there should only be one reason for a class to change.所以(至少就SRP而言)如果一个类只有一个原因可能会改变,那么它有很多方法。决定SRP是否适用(等效地,决定什么构成一个改变的类别的原因)与所有这些原则一样,是品味和判断的问题。
例如,在我刚刚链接到的SRP的原始描述中,我发现SRP在玩具保龄球游戏中的应用是无偿的 - 如果保龄球规则发生变化,分开的类别将全部改变。另一方面,将几何计算与渲染UI分开应该对任何人都有意义。
我不知道您的代码库,但每种方法的类听起来都不对。
SRP与DRY有什么关系?
SRP的反转是,如果两个类因同样的原因而改变(如在保龄球游戏中),也许它们应该是一个类。这本身并不与DRY有关(它是关于责任的扩散,而不是代码的重复),但是:如果有人在编写或提取第二课时忘记了干,那么你你可能会注意到你改变这两个班级(或者更糟糕的是,当你忘记改变一个班级并在生产中发现时),并提醒他们为什么DRY很重要。
我是否应该重复删除("干掉")我负责任的课程?
是。相同代码的副本会导致错误。不要不合理;如果提取一些重复项使您的程序更难理解并增加其代码行数,那么您肯定会过度使用它。但是要提取重要的重复内容,您只需要测试一次,并在更改时更改一次。
但是,要始终明确提取的方法与需求的关系。如果您需要以相同的方式对报告和税收计算的某些值进行求和,请不要调用方法totalForReporting
或将其称为total
并将其放在ReportingService
上,然后从您的TaxService
调用它 - 想要更改报告而不是税务计算的人不会考虑检查该方法是否在其名称不会引起您期望的上下文中使用。相反,将该方法称为transactionTotal
之类的通用方法,或者只需将其称为total
并将其放在GeneralLedgerService
上,它将完全(咳嗽)清楚它的作用是什么以及何时它应该改变与否。
关注需求进行重复数据删除会增强您的域模型,因为您始终要小心将代码与适当的域概念相关联,无论是模型还是服务等等。