我试图理解“单一责任”原则,但是我在理解这一概念时遇到了困难。我正在阅读《 Lucian-Paul Torje; Adrian Ianculescu; Kamalmeet Singh所著的Java设计模式和最佳实践》这本书。
在本书中,我正在阅读“单一责任原则”一章, 他们的汽车类别如下所示:
他们说Car具有Car逻辑和数据库操作。将来,如果我们要更改数据库,则需要更改数据库逻辑,并且可能还需要更改汽车逻辑。反之亦然...
解决方案是创建两个类,如下所示:
我的问题是,即使我们创建两个类,也可以考虑在类CAR上添加一个名为“ price”的新属性[或者将属性“ model”更改为“ carModel”],那么您是否认为我们也需要更新CarDAO类,例如更改SQL等。
那么SRP在这里有什么用?
答案 0 :(得分:6)
好问题。
首先,请记住,这是本书中的一个简单例子。读者应对此稍作扩展,并想象更复杂的情况。在所有这些情况下,进一步想象您不是团队中唯一的开发人员;相反,您是在一个大型团队中工作,开发人员之间的通信通常采用协商类接口即 API,公共方法,公共属性,数据库模式的形式。另外,您经常会担心回滚,向后兼容性以及同步发布和部署。
例如,假设您要交换数据库,例如,从MySQL交换到PostgreSQL。使用SRP,您将重新实现CarDAO
,更改使用的特定于方言的SQL,并保持Car
逻辑不变。但是,您可能必须对配置进行一些小的更改,才能告诉Car使用新的PostgreSQL DAO。合理的DI框架可以简化这一过程。
在另一个示例中,假设您希望将CarDAO委派给另一位开发人员以与memcached集成,从而使读取(尽管最终保持一致)很快。同样,该开发人员无需了解关于Car
中的业务逻辑的任何知识。相反,他们只需要在CarDAO
的CRUD方法后面进行操作,并可能在CarDAO
API中声明其他一些具有不同一致性保证的方法。
在另一个示例中,假设您的团队聘请了一位专门从事合规法律的数据库工程师。为即将进行的首次公开募股做准备,数据库工程师的任务是保留公司35个数据库中所有表的所有更改的审核日志。使用SRP,我们勇敢的DBA不必担心使用任何表的任何业务逻辑;取而代之的是,可以使用装饰器或其他方面编程技术将其变异跟踪魔术巧妙地注入DAO中。 (顺便说一下,这也可以在SQL接口的另一端完成。)
好的,最后一个-假设现在有一位系统工程师被带到团队中去,并负责在AWS的多个区域(数据中心)中分担这些数据。该工程师甚至可以进一步完善SRP,并添加一个组件,该组件的唯一作用是针对每个ID告诉我们每个实体的归属区域。每次我们进行跨区域读取时,新组件都会增加一个计数器。每周,都有一个自动化工具将跨区域频繁读取的数据迁移到新的本地区域,以减少延迟。
现在,让我们进一步发挥想象力,并假设业务蒸蒸日上-突然间,您正在为一家财富500强公司工作,该公司的多个部门遍布多个国家。财务部的业务分析师希望使用您的表格在首次公开募股后的投资者报告中绘制汽车销量的季度增长。除了允许他们访问Car
(因为用于报告的逻辑可能与用于准备要在Web UI上呈现的数据的逻辑不同)之外,您还可以为{{ 1}},其中包含您现在必须跨部门边界维护的精心挑选的公共属性的简短列表。上帝禁止您必须重命名这些属性之一:为3个月的日落计划做好准备,并准备好许多可悲的仪表板和深夜升级。 (并且请不要直接让他们访问实际的SQL表,因为隐式假设是整个表都是 the 公共接口。)糟糕,我可能会感到恐惧。
一个必然结果是,如果您需要更改CarDAO
中的业务逻辑(例如,添加一种方法,在尴尬的召回之后计算每辆特斯拉的较低销售价格),您不会碰Car
,因为CarDAO
与数据访问无关。
其他阅读:CQRS
答案 1 :(得分:2)
要添加新属性,仅当该属性应保存到数据库时才需要更改两个类。如果它是业务逻辑中使用的属性,则无需更改DAO。同样,如果您将数据库从一个供应商更改为另一供应商,或从SQL更改为NoSQL,则仅需在DAO类中进行更改。而且,如果您需要更改某些业务逻辑,则只需更改Car
类。
答案 2 :(得分:2)
Single responsibility principle是
一个班级只有一个改变的理由。
牢记这一原则通常会导致规模较小且凝聚力强的类,这反过来意味着更少的人需要同时处理这些类,并且代码变得更强大。
在您的示例中,将数据访问和业务逻辑(价格计算)逻辑分开,意味着您进行更改时不太可能破坏彼此。