【发布时间】:2017-02-26 04:24:27
【问题描述】:
我正在设计一个订单系统,状态设计模式似乎很合适,因为订单可以更改其状态,从而更改订单允许的功能。下面是我的基本类图:
我不喜欢这种方法,因为客户看不到某个方法是否受支持并且违反了 Liskov 原则。我在下面创建了一个替代方案:
我更喜欢这个,但客户端仍然必须检查是否支持某个方法。但是他们仍然可以调用不受支持的方法并获得异常。这是否仍然违反 Liskov 原则?
是否有更好的设计符合 Liskov 并防止用户为特定状态调用无效方法?
【问题讨论】:
-
我不明白您所说的“无法查看是否支持某个方法”是什么意思。具体的 OrderState 都将实现 OrderState 方法。当状态当前不允许操作时,它们中的一些会引发异常。这并不违反 LSP imo。另外,我看不出这有什么不同,而不是直接引发 UnsupportedOpEx,而是首先调用其中一个 can* 方法然后引发它。 Imo,允许 Order 的任何消费者调用 can* 方法更糟糕,因为它将责任移到了 Order 对象之外。
-
在类图 1 中,客户端无法检测操作是否对特定状态有效。那么就没有办法知道是否应该显示支付按钮或取消按钮。在我对 LSP 的理解中,抛出 notSupportedException 是破坏 LSP 的常用方法。这是因为子类型不做所说的,因此子类型不能替代它的基类型。
-
具体的
OrderStates都将实现OrderState接口和方法。所有这些方法都将——如果可能的话,通过接口契约——潜在地引发异常。因此,您可以将 OrderState 的任何具体子类型替换为另一个。因此,您不会违反 Liskov 的替代原则。顺便说一句,您可以使用相同的模式来绘制按钮。只需将按钮渲染器传递给 OrderState 并让它从具体的 OrderState 返回正确的按钮,例如Confirmed 将告诉 ButtonRenderer 呈现支付按钮等。 -
我查找了 LSP 的定义“如果 S 是 T 的子类型,则类型 T 的对象可以替换为类型 S 的对象(即,类型 S 的对象可以替换类型 T)而不改变该程序的任何所需属性(正确性、执行的任务等)”违反了正确性,因为您在订单上调用 pay 方法并且您希望您正在支付订单。相反,当前状态将永远无法支付。因此这会破坏系统的正确性。
-
参见programmers.stackexchange.com/questions/181922/…,特别是programmers.stackexchange.com/a/181941/49178 - 如果预期会出现异常,则不会违反正确性。否则,任何引发异常的方法都会违反 LSP。
标签: oop architecture liskov-substitution-principle state-pattern