【发布时间】:2018-07-08 08:43:23
【问题描述】:
SOLID 中的 L 和 D 都鼓励我们根据合同而非实际实现进行编程。但这是否意味着接口使用者不应该知道实现,或者他不应该依赖实现来做合同中没有明确规定的事情?
我的意思是,我们可以有一个方法在 DB 中创建一个新的 NumericParameter,但它的接口只是这么说!它并没有说 NumericParameter 实际上是跨越 2 个表的继承实体,或者该方法还创建了一个更多相关实体以保存有关创建的实体的更多数据。这些是实现细节。
很清楚为什么不应该依赖实现来做某事。但也许依赖实现不做某事是合理的(即使合同中没有说明?)否则,你将如何修改你的代码?任何时候你添加一些活动,它都可能与你调用的其他一些方法和服务中发生的事情发生冲突。就像,你读了一个“更新”的数据库行,然后调用 foo() 然后写回一行并进行一些修改,但似乎 foo() 已经对同一行进行了一些更改——在这个事务中——他们将被覆盖。
另一方面,可以更改实现。如果某个消费者依赖它不做某事,那么在某些时候这种依赖可能会中断。这意味着,我们不仅要检查正在编辑的代码中调用了哪些代码,还要检查代码的可能调用者。我们必须详细了解触发此代码的任何事务中可能发生的一切。
不知何故,我认为那是一种气味,但没有它你怎么活?我通常会尝试忽略实现细节,但在很多情况下都会导致一些冲突。
【问题讨论】:
-
你说的做一些没有在合同中规定的事情是什么意思?它收到的数据有什么问题吗?跟外面的世界有什么关系?与它的调用者?在
foo()示例中,我们希望依赖项不会做什么? -
一个更新的例子。一部分逻辑删除实体A;其他一些部分修改了由 A 引用的 B。由于 JPA API 的性质,如果引用的实体包含引用它的所有实体的集合,则该集合(缓存,一旦从 DB 中读取)必须与也缓存在此事务中的实际实体。因此,尽管这两个逻辑部分没有自然冲突,删除实体 A 然后保持 B 的当前状态(现在失去一致性,因为它仍然包含对 A 的引用)会引入冲突。
-
这个例子向我们展示了这一点:任何修改某个 B 的代码都必须依赖它调用的其他代码才能不删除任何 A。如果它不能依赖它,那么它的作者就不能确定他不会通过编写这段代码来引入冲突。
-
或者,更简单的是,任何从 DB 读取某个实体的代码都必须依赖它执行的任何其他服务都不会尝试从 DB 中删除该实体(这可能是后者的“内部实现细节”服务)。
-
你误解了我的意思。 JPA,而不是你,必须尊重他们的合同。但并发访问问题与合约或 JPA 内部实现方式无关。它们与您(客户)如何使用 JPA 以及何时使用有关。
标签: oop architecture solid-principles