异常的里氏替换原则

Liskov Substitution Principle for Exception

我正在阅读 'Agile Principles, Patterns and Practices' 一书中关于 LSP 的内容。 它指出:

"A routine redeclaration [in a derivative] may only replace the original precondition by one equal or weaker, and the original post-condition by one equal or stronger."

The term weaker can be confusing. X is weaker than Y if X does not enforce all the constraints of Y. It does not matter how many new constraints X enforces.

我们如何在异常的上下文中理解它?

LSP 适用于类型。所以在大多数 OOP 语言中都是 classes。然后可以通过三种方式来考虑您的问题:

1.异常被认为是 type

异常类型,例如 C++ 中的 std::exception,可以派生为更专门的异常。为了便于错误处理,应使用代码 LSP。

异常的行为通常很差,只是传输一些关于错误条件的额外信息,所以一般来说这并不太难。

2。被视为失败先决条件的异常

Exception应该对应于正常情况下不会出现的异常情况。因此,引发异常意味着预期的正常条件不存在。

所以在派生类型中引发异常的条件应该等于或弱于一般类型。

让我们来看一个极端的例子。假设在给定例程的基础 class 中没有预见到异常。您会期望甚至指定 nothrow。使用此例程的代码将认为它是安全的,并且不会预见到任何异常捕获。假设您随后将此 class 派生为抛出异常的代码(即前提条件更强,限制性更强):如果引发异常,则为基础 class 编写的代码将措手不及,并且基础 class 的通用代码可以用专门的 class 破解。所以LSP会被打破。

3。被视为特殊结果的异常 / post-condition

您可能会争辩说,在某些情况下,异常是一种特殊的 post 条件。 return 值的替代方法。

我会对这种解释感到不舒服(因为这不是许多语言设计者的理解,请参阅关于 nothrow 的讨论)。但是我没有进一步的 objective 参数来使它无效。

由于 LSP 是关于合同的,因此您可以做出此设计决定。在这种情况下,更专业的 class 可以抛出更专业的异常(因此推理将基于异常类型)。但是派生的 class 真的应该至少抛出与原始异常一样多的异常吗?这听起来违反直觉。转到 2。