【问题标题】:Should client check postcondition/should called method check precondition?客户应该检查后置条件/应该调用方法检查前置条件吗?
【发布时间】:2013-05-01 18:02:37
【问题描述】:

公共方法的前置条件后置条件构成了这个方法和它的客户端之间的契约。

1.根据to调用者不应该验证后置条件被调用方法不应该验证前置条件 em>:

让我们回忆一下正方形的前置条件和后置条件 根函数 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) 由于 client 有责任满足方法的先决条件被调用方法 是否也应该检查 先决条件满足了吗?

b) 由于被调用方法负责传递满足后置条件的结果,因此调用者是否应该检查后置条件

2.第一篇文章中提到的一个好处是“前置条件和后置条件可以用来在OOP中划分类之间的责任”,我理解这也是说它不是被调用的方法负责验证前置条件,而调用者不负责验证后置条件

但是不遵守这样的理念会使我们的代码更容易受到攻击,因为它盲目地相信对方(对方是 callermethod )会兑现承诺吗?

3.如果调用者/被调用方法不盲目信任对方,那么我们不要失去后置条件前置条件提供的很多好处,因为现在被调用的方法必须负责检查前置条件并且调用者必须负责验证后置条件

谢谢

编辑

3.

如果调用者/被调用方法不盲目信任对方,那么不要 我们失去了后置条件提供的大部分好处,并且 先决条件,既然现在被调用的方法必须承担责任 还要检查前提条件,来电者必须承担责任 验证后置条件?

调用者不需要验证后置条件,因为它们应该是 由调用的方法确保。被调用的方法确实需要验证 前提条件,因为没有其他方法可以执行合同。

a) 你是否假设 postcondition 应该只声明/保证 return value 是指定类型或null(如果 return value 可以为空)?除了 return value 将是什么类型之外,postconditions 是否也不能说明其他事情(无法通过类型系统验证),例如是否 return值指定范围内(例如:不能后置条件也声明int类型的返回值将在10-20 的范围)?在这种情况下,客户不需要检查后置条件吗?

b) 那么我们能否说第一篇文章声称​​被调用的方法不应该检查前置条件是错误的?

2。编辑

不,后置条件可以是任何东西,而不仅仅是空检查。任何一个 方式,客户端可以假设后置条件已被验证 这样,例如,您不需要验证 int 范围,如果 合同声明已得到保证。

a) 您之前说过 前置条件 需要通过 调用的方法 进行检查,以使代码不那么容易受到攻击,但我们不能也推理 调用者需要验证一个后置条件(例如验证返回的int值在后置条件所承诺的范围内)以使调用者的代码 不那么脆弱?

b) 如果客户可以盲目信任 postcondition 提出的声明(我会说当 postcondition 提出类似 return value is within一些范围),为什么被调用方法也不能相信调用者会满足被调用方法的先决条件

【问题讨论】:

    标签: domain-driven-design preconditions post-conditions


    【解决方案1】:

    a) 由于客户有责任履行 一个方法的前置条件,应该被调用的方法也检查是否 前提条件是否满足?

    是的,确保满足先决条件是客户端的责任,但是被调用的方法必须验证这一点,因此示例中的 null 检查。

    b) 因为传递结果是被调用方法的责任 满足后置条件,调用者应该检查 后置条件?

    调用者应该能够依赖被调用方法的契约。在您提供的示例中,方法 GetUserWithIdOf 确保满足后置条件,否则抛出异常。存储库本身没有后置条件,即它总是返回用户,因为可能找不到用户。

    2.第一篇文章中提到的一个好处是“前置条件和后置条件可以用来划分 OOP 中类之间的责任”,我也理解为 说它不是被调用方法的责任来验证 前提条件,调用者不负责验证 后置条件。

    验证前置条件仍然是被调用方法的责任,因为它们通常不能被类型系统验证。诸如Eiffel 之类的语言提供了更大程度的静态合约验证,在这种情况下,人们可以利用该语言来强制执行前置条件。就像在 Java/C# 中您可以强制方法参数是给定类型一样,Eiffel 将这种类型的验证扩展到更复杂的合约声明。

    但是不坚持这样的理念会使我们的代码更容易受到攻击, 因为它盲目地相信对方(对方是 无论是调用者还是方法)都会兑现其承诺?

    是的,这就是必须验证前置条件的原因。

    3.如果调用者/被调用方法不盲目信任对方,那么我们不会失去很多后置条件和 先决条件,既然现在被调用的方法必须承担责任 还要检查前提条件,来电者必须承担责任 验证后置条件?

    调用者不需要验证后置条件,因为它们应该由被调用的方法来确保。被调用的方法确实需要验证前置条件,因为没有其他方法可以强制执行合同。

    更新

    a) 不,后置条件可以是任何东西,而不仅仅是空检查。无论哪种方式,客户端都可以假设后置条件已经过验证,例如,如果合同声明已确保 int 范围,则无需验证 int 范围。

    b) 我会说是的。引用:

    如果传递一个负数,平方根函数应该做 没有什么可处理的。

    if 表明被调用的方法已经进行了某种验证。什么都不做是无声的失败,可以是anti-pattern

    随后的引用:

    如果操作的先决条件失败,则归咎于调用者 如果操作的后置条件失败,则调用操作

    将失败的先决条件归咎于调用者的唯一方法是首先确定先决​​条件失败。由于被调用的方法“拥有”这个前提条件,它应该是标记失败的最后一站。

    更新 2

    a,b) 调用者可以信任后置条件的原因是因为后置条件可以通过被调用的方法来保证。被调用的方法是声明和拥有合约的方法。被调用方法不能信任调用者的原因是没有人保证满足先决条件。被调用的方法并不知道它可能拥有的所有不同的调用者,因此它必须自己验证。

    【讨论】:

    • 这是合理的论点。但是,如果您的代码调用了某个新手程序员编写的类的方法,您会信任被调用的方法(即信任这个新手程序员)来满足承诺的后置条件还是信任(即您,调用者,不要检查后置条件 ) 仅在“摘录”编写的方法中?
    • 如果您调用的代码无法信任,那么是的,您也必须重新验证后置条件。对于外部系统尤其如此。但是,如果您正在调用具有测试的本地代码,那么您应该能够依赖合同。否则,合同的意义何在?
    • 非常感谢您的回答
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-06-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多