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

Мне сложно понять принцип замещения Лискова, и мне было интересно, нарушает ли следующий код принцип замещения Лискова?

public class Task {

     String status = "Ready"; // One of "Ready", "Started", and "Closed"

     public void setStatus(String newStatus) {
          status = newStatus;
     }
     public void cancel() {
          status = "Closed";
     }
}
public class ProjectTask extends Task {

     @Override
     public void cancel() {
          if (status.equals("Started")) {
               throw new RuntimeException("Cannot cancel a started project task.");
          }

          super.cancel();
     }
}

Я думаю, что это так, поскольку подкласс не ведет себя как базовый класс при его замене, а также потому, что он генерирует исключение RunTimeException?

Я не совсем уверен, и мне было интересно, верно ли мое предположение

1 ответ

Решение

Подкласс не должен вести себя так же, как базовый класс. Он должен реализовать контракт базового класса.

К сожалению, вы не задокументировали контракт базового класса, поэтому я не могу сказать, верен он или нет. Если это так:

public class Task {
    ...

    /**
     * Attempt to cancel the task.
     *
     * @throws RuntimeException if the task is not in a cancellable state
     */
    public void cancel() {
        status = "Closed";
    }
}

... тогда все в порядке.

Контракт означает, что любой, кто звонит Task.cancel необходимо ожидать исключения.

Видите ли, LSP - это не только то, что делает базовый класс или что делает подкласс. Речь идет о коде, который использует эти вещи.

LSP говорит, что когда метод или конструктор объявляется для Task в качестве аргумента то декларация обещает, что работает не только с прямым Task реализации, но все допустимые реализации подкласса, потому что ProjectTask Это Task.

Ваша задача как инженера - обеспечивать выполнение этих обещаний.

Другие вопросы по тегам