执行除了合同还要知道什么?

What to know of implementation besides contract?

SOLID 中的 L 和 D 都鼓励我们根据合同而不是实际实施进行编程。但这是否意味着接口使用者不应该知道实现,或者只是他不应该依赖实现来做合同中未明确规定的事情?

我的意思是,我们可以有一个方法来在数据库中创建一个新的 NumericParameter,但它的界面只说了这个!它并没有说 NumericParameter 实际上是一个跨越 2 个表的继承实体,或者该方法还创建了一个更多的相关实体来保存有关创建的实体的更多数据。这些是实施细节。

很清楚为什么不应该依赖实现来做某事。但也许依靠实现 NOT 做某事是合理的(即使它没有在合同中说明?)否则,您将如何修改您的代码?任何时候您添加一些 activity,它都可能与您调用的其他一些方法和服务中发生的事情发生冲突。就像,您读取了一个数据库行 "for update",然后调用 foo() 然后写回一行并进行一些修改,但看起来 foo() 已经对同一行进行了一些更改 - 在这个事务中 - 并且它们将被覆盖。

另一方面,可以更改实现。如果某些消费者依赖于它不做某事,那么在某些时候这种依赖性可能会中断。这意味着,我们不仅要检查从正在编辑的代码中调用了哪些代码,还要检查代码的可能调用者。触发此代码的任何交易中可能发生的一切,我们必须详细了解。

不知怎的,我觉得那是一种气味,但没有它你怎么生活?我通常试图忽略实现细节,但在很多情况下都以一些冲突告终。

这在"opinionated"的边缘,但我认为

的事实答案

he should not rely on implementation doing something not stated in a contract explicitly?

应该是 - 正好。这就是此处的 core 元素。编写接口的人同时至少编写一个实现是很常见的。并且在写下接口时可能已经设计了一些实现(至少在您的脑海中)。所以 "knowing about the implementation" 是你在现实世界中最经常无法避免的事情。所以最好专注于陈述的第二部分。

除此之外:当您发现合同模棱两可时,请不要花时间担心不同的解释。而是用你的精力澄清合同,使其成为"clear enough"实施应该做什么或不做什么。

我认为 SOLID 的关键在于你应该尽可能地使用 所有 原则,而不是孤立地选择一两个原则。你用 foo() 给出的例子是一个问题,因为你的代码的两个区域处理同一个数据库记录。我的解释是,这违反了 SOLID 中的 S。

But does that mean an interface consumer should not know the implementation, or just that he should not rely on implementation doing something not stated in a contract explicitly?

前者。然而,这种依赖性是否可以避免接触他们甚至不知道客户关心的外部事物?合同与其说是 "don't move my cheese",不如说是 "give me back something with the shape I expect, no matter which way you do it".

我看到的唯一其他答案是使用纯(无副作用)函数,但我们不再真正处于 OOP 领域。

好吧,我总结一下大家的智慧。

1) 通常,一个方法的所有重要影响要么是其合同的一部分(或应该是),要么是由环境决定的(就像 JPA 的删除会干扰 JPA 对其他实体的修改)。如果是前者,那么合同会告诉我们会发生什么,如果是后者,开发人员应该知道他自己定义的环境的影响。因此,在这两种情况下,他都应该知道可能的冲突 不知道实现。一个设计得当的方法几乎不会造成一些与其合同和 environment/settings/etc 完全无关的重大影响,或者至少我没有想到或这里的任何其他人都没有提到过这样的例子。当然,除非那个方法被非常熟悉它的人使用并且依赖于它的实现;但在这种情况下,我当然必须知道实现,我的问题不适用。

2) 在我的问题中,我提到了 "inherited entity spanning over several tables" 和 "creates one more entity" 等实现细节。好吧,JPA 继承的特定问题是环境的一部分;创建额外的实体应该是合同的一部分(如果实体是由其他人推荐的)或者不会造成任何干扰(如果它是严格私有的东西),或者如果它是配置引入的某些 "aspect" 的产物,则应该是环境的一部分在原始方法的逻辑之上。

因此,我最初问题的答案是 "no need to know implementation details"(除非你必须使用紧耦合 类)和 "given properly defined contracts and properly designed methods, you can live without that because you should know everything you need from contracts and environment"。