该代码是否违反《里斯科夫替代原则》?

时间:2019-12-14 02:42:06

标签: design-patterns solid-principles liskov-substitution-principle

我在理解Liskov替代原理上有些困难,想知道以下代码是否违反Liskov替代原理?

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 个答案:

答案 0 :(得分: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实现,而且适用于所有有效的子类实现,因为ProjectTaskTask

您作为工程师的工作是确保兑现这些诺言。