在我的例子中,Liskov替换原则是否被违反?

时间:2017-02-15 12:24:03

标签: oop solid-principles ooad liskov-substitution-principle

我想知道我应该如何组织我的两个课程。

  • 其中一个代表一个Knife:只是一个简单,坚实,基本的,就像一把菜刀。
  • 另一个是PocketKnife,其状态为已打开已关闭
class Knife{
  public function cut() {/* do the cutting */}
}
class PocketKnife extends Knife{
  private $opened = 0; // 0/1
  // ...
  public function cut() {
    if ($this->opened) {
      parent::cut();
    }
  }
}

我的代码中的所有类都不是抽象的。

这个例子是否违反了LSP?

在我看来确实如此,因为cut()操作的后置条件应为:

  1. 刀的刀片有点老了"切割后
  2. 某些物体必须对它造成一些伤害(例如,如果它是某种游戏)
  3. 但是当已关闭状态的PocketKnife时,我们不会有这些后置条件。或者我错了吗?

2 个答案:

答案 0 :(得分:1)

是否违反LSP,取决于" cut"的定义。是(不应该)。如果操作的后置条件是以下必须为真:

  1. 刀的刀片有点老了"切割后
  2. 某些物体必须对它造成一些伤害(例如,如果它是某种游戏)
  3. 然后,当关闭"关闭时,PocketKnife不符合这些条件。因此,PocketKnife无法在任何地方替换Knife并且LSP被破坏。

    如何解决?

    嗯,这取决于上下文,需要更多信息。但是,一个例子可能是这样的:

       class Knife{
          public function cut() {/* do the cutting */}
        }
    
        class PocketKnife extends Knife{
    
          private $opened = 0; // 0/1
          // ...
    
          public function cut() {
            if (!$this->opened) {
    
              // state is changed for cut to be performed.
              $this->opened = 1; 
    
              parent::cut();
    
              // may need to close again, after operation.
            }
          }
        }
    

    这样,LSP就不会被破坏。再一次,这个例子只是提出了解决这类问题的方法。

答案 1 :(得分:0)

Liskov替换原则(最简单的OOP设计指南之一)简单地指出任何子类型必须可以替代其父类而不破坏程序。

如果你有像someFunc(Knife k)这样调用k.cut()的方法,你可以将Knife或Pocketknife或WhateverKnife传递给someFunc方法并使程序正常工作,那么你就不会违反LSP。