公共方法的前提条件和后置条件形成了此方法与其客户端之间的契约。
1.根据to,调用者不应验证后置条件,调用方法不应验证前提条件:
让我们回顾一下广场的前提条件和后置条件 根函数sqrt,如程序49.2所示。一个调用的函数 sqrt负责将非负数传递给函数。如果 传递负数,平方根函数应该这样做 什么都没有处理它。另一方面,如果是非负面的 number传递给sqrt,sqrt负责提供 满足后置条件的结果。因此,sqrt的调用者 应该什么也不做,以检查或纠正结果。
如果操作的前提条件失败,则责备调用者 如果操作的后置条件失败,则归咎于被调用的操作
但正如another article中包含的代码所示,调用方法会验证前置条件:
/// <summary>Gets the user for the given ID.</summary>
public User GetUserWithIdOf(int id,
UserRepository userRepository) {
// Pre-conditions
if (userRepository == null)
throw new ArgumentNullException(
"userRepository");
if (id <= 0)
throw new ArgumentOutOfRangeException(
"id must be > 0");
User foundUser = userRepository.GetById(id);
// Post-conditions
if (foundUser == null)
throw new KeyNotFoundException("No user with " +
"an ID of " + id.ToString() +
" could be located.");
return foundUser;
}
a)由于客户端负责实现方法的前提条件,因此调用方法也要检查是否 >先决条件是否已实现?
b)由于调用方法负责提供满足后置条件的结果,调用者应该检查后置条件
2.第一篇文章中提到的一个好处是“前提条件和后置条件可以用来划分OOP中的类之间的责任”,我理解这也说它不是调用方法负责验证前提条件,调用者负责验证后置条件。
但不坚持这种理念会使我们的代码更容易受到攻击,因为它盲目地信任另一方(其他方是来电或方法)会履行承诺吗?
3.如果来电/被叫方法不盲目信任其他方,那么我们不会失去后置条件和前置条件提供的大部分好处,因为现在调用方法必须承担检查前提条件和调用者必须承担验证后置条件的责任的责任吗?
感谢
修改
3
如果来电/被叫方法不盲目信任其他方,则不要 我们放弃了后置条件和提供的大部分好处 先决条件,因为现在所谓的方法必须承担责任 还要检查前提条件,来电者必须承担责任 验证后置条件?
来电者不需要验证后期条件,因为它们应该是 通过被叫方法确保。被调用的方法确实需要验证 前提条件,因为没有其他方式来执行合同。
a)您是否假设后置条件只应声明/保证返回值具有指定类型或null
(如果返回值是可以为空的)?除了返回值的类型之外,后置条件还不能声明其他内容(无法通过类型系统验证),例如是否返回值在指定范围内(例如:不能后置条件也表明类型为int
的返回值将在10-20
)的范围内?在这种情况下,客户端是否还需要检查后置条件?
b)我们可以说第一篇文章错误地声称调用方法不应该检查前置条件吗?
2。修改
不,发布条件可以是任何内容,而不仅仅是空检查。或 方式,客户可以假设已经验证了后置条件 所以,例如,如果你不需要验证int范围 合同规定已经确保。
a)您之前曾声明前置条件需要通过被调用的方法进行检查才能使代码不那么容易受到攻击,但我们也不能推断调用者需要验证后置条件(例如,确认返回的int
值在后置条件承诺的范围内),以便调用者的代码不那么脆弱?
b)如果客户可以盲目地信任后置条件所做的声明(我说当后置条件声明返回值时,它是盲目信任一些范围),为什么调用方法也不能相信调用者将实现被调用方法的前提条件?
答案 0 :(得分:2)
a)因为客户有责任履行 一个方法的前提条件,应该调用方法也检查是否 满足前提条件?
是的,客户有责任确保满足前提条件,但被调用的方法必须验证这一点,因此示例中的空值检查。
b)因为传递结果是被调用方法的责任 如果调用者检查了,则满足后置条件 后置条件?
调用者应该能够依赖被调用方法的契约。在您提供的示例中,方法GetUserWithIdOf
确保满足后置条件,否则抛出异常。存储库本身没有后置条件,它将始终返回用户,因为可能找不到用户。
2.第一篇文章中提到的一个好处是“先决条件和后置条件可以用来划分 OOP课程之间的责任“,我也理解 说验证的方法不是责任 先决条件,并且调用者无需进行验证 后置条件。
调用前置条件仍然是被调用方法的责任,因为它们通常不能由类型系统验证。 Eiffel等语言提供了更大程度的静态合同验证,在这种情况下,可以使用该语言来强制执行前提条件。就像在Java / C#中一样,您可以强制方法参数属于给定类型,Eiffel将此类验证扩展到更复杂的合同声明。
但是不坚持这种理念会使我们的代码更容易受到攻击, 因为它盲目地相信另一方(另一方是 无论是呼叫者还是方法)都能实现其承诺?
是的,这就是必须验证前提条件的原因。
3.如果来电/被叫方法不盲目信任其他方,那么我们不会失去后置条件提供的大部分好处 先决条件,因为现在所谓的方法必须承担责任 还要检查前提条件,来电者必须承担责任 验证后置条件?
调用者不需要验证后置条件,因为它们应该通过被调用的方法来确保。被调用的方法确实需要验证前置条件,因为没有其他方法可以强制执行合同。
<强>更新强>
a)不,发布条件可以是任何内容,而不仅仅是空检查。无论哪种方式,客户端都可以假设后置条件已经过验证,例如,如果合同声明已经确定,则不需要验证int范围。
b)我会说是的。引用:如果传递负数,则应该使用平方根函数 什么都没有处理它。
if 表明被调用的方法已经进行了某种验证。什么都不做是一个无声的失败,可以是anti-pattern。
后续引用:
如果操作的前提条件失败,则责怪调用者 如果操作的后置条件失败,则调用操作
将失败前置条件归咎于调用者的唯一方法是首先确定前置条件失败。由于被调用方法“拥有”这个前置条件,因此它应该是标记失败的最后一站。
更新2
a,b)调用者可以信任后置条件的原因是因为调用方法可以确保后置条件。被调用的方法是声明和拥有合同的方法。被调用方法不能信任调用者的原因是因为没有人能够保证满足前置条件。被调用的方法不知道它可能具有的所有各种调用者,因此它必须自己进行验证。