【问题标题】:If Address inherits from PhoneNumber, what OOP principle(s) does it violate?如果 Address 继承自 PhoneNumber,它违反了哪些 OOP 原则?
【发布时间】:2013-02-24 06:46:50
【问题描述】:

有一本书说有一个PhoneNumber 类,然后我们会定义一个继承自PhoneNumberAddress 类,我曾经说过,我们不能这样做,因为地址不是电话号码,要继承,必须是“是”关系。如:狗是动物,我们可以让Dog继承自Animal

但既然我们必须遵循LSP -- Liskov Substitution Principle,那么“是”规则实际上并不是这里的决定因素,因为正方形“是”矩形(宽度 == 高度),但 LSP 说我们可以' t 定义一个Square 类并从Rectangle 类继承。英文简单的解释,我想,是对象aRect可以响应消息setWidthAndHeight(w, h),但是aSquare不能正确响应,让整个程序正常运行。

令人惊讶的是,继承PhoneNumber 类的Address 类违反了“is a”关系,但并不违反LSP。那么正式地说,它违反了哪些 OOP 原则?

【问题讨论】:

  • 它唯一违反的是常识,但在了解所有系统及其组件之前,不能仅根据 2 个对象来判断设计。
  • 我认为 OOP 的 5 个原则:S.O.L.I.D.是我们不只是使用常识,为所欲为,而是遵循原则
  • 在不了解更多细节的情况下很难回答这个问题,但如果Address 继承自PhoneNumber,它似乎有多个更改的理由,这违反了单一责任原则。此外,谁说 SOLID 是 OOP 的原则(考虑 GRASP、Demeter 法则、DRY、KISS)。
  • “THE”代表什么? :-)
  • @BobHorn It does。如果在w 不等于h 时抛出异常,则表示您正在加强子类型中的前置条件,根据前置条件和后置条件的规则,这是不允许的(另一个参考:p. 7 of this ObjectMentor article)。

标签: oop object-oriented-analysis liskov-substitution-principle


【解决方案1】:

首先,这确实确实违反了 LSP。

通常,您不会期望能够用地址替换电话号码。这就是 cmets 中每个人都在谈论的“常识”。

OOP 理论的要点是,遵循正式规则将使您的类变得健壮,以应对变化和奇怪的用例等事情。即使书中的示例实际上并没有在违反 LSP 的情况下崩溃,我想如果您尝试扩展该类架构,它也会很快崩溃。因此,为避免未来课程出现潜在错误,您应该遵循 LSP - 即使选择不这样做也不会立即破坏任何内容。

第二,它违反了ISP(接口隔离原则)。

这表明一个类中可用的方法集应该是该类的对象运行所需的最小值

如果 Address 类继承(或可能合理地继承)一堆在处理实际街道地址时从未使用过的 PhoneNumber 方法(例如 getAreaCode() 方法,该方法对于住宅地址是未定义的),那么它的接口不是最小的。

这里的要点是 OOP 原则实际上只是指导方针。完全有可能编写违反 SOLID 原则但实际上不会引入错误的奇怪示例代码。这并不意味着您正在规避规则。这只是意味着一旦您尝试扩展类,您最终会遇到更多错误。

【讨论】:

    【解决方案2】:

    使用继承或扩展主要有两个原因。

    1. 重用实现(用于 DRY)
    2. 子类型(LSP 相关)

    我不知道所有的原则,但对于你的情况,它违反了@mpm 评论的常识。

    因为即使您的代码满足所有原则,它仍然可能是不合适的。换句话说,原则不能包罗万象。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-11-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多