Нарушен ли в моем примере принцип подстановки Лисков?

Интересно, как я должен организовать свои два класса.

  • Один из них представляет собой 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. на каком-то объекте должны быть какие-то повреждения (например, если это какая-то игра)

Но если PocketKnife находится в закрытом состоянии, у нас не будет этих пост-условий. Или я ошибаюсь?


person Neitrino    schedule 15.02.2017    source источник


Ответы (2)


Нарушает ли это LSP или нет, зависит от того, что является определением «вырезать» (не должно быть). Если постусловие для операции состоит в том, что ДОЛЖНО выполняться следующее:

  1. лезвие ножа немного "стареет" после разрезания
  2. на каком-то объекте должны быть какие-то повреждения (например, если это какая-то игра)

Тогда 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 не будет нарушен. Опять же, пример просто дает представление о способах решения такой проблемы.

person Nazar Merza    schedule 15.02.2017

Принцип замещения Лискова (одно из самых простых правил проектирования ООП) просто гласит, что любой дочерний тип должен быть заменяемым для своего родителя без нарушения программы.

Если у вас есть такой метод, как someFunc(Knife k), который вызывает k.cut(), и вы можете передать Knife, Pocketknife или WhateverKnife в этот метод someFunc и заставить программу работать правильно, то вы не нарушаете LSP.

person user2321864    schedule 15.02.2017
comment
Это не отвечает на его вопрос, а просто повторяет идею/принцип LSP. Нарушает ли его кодекс? Почему? - person Dioxin; 15.02.2017