design-patterns - 该代码是否违反了 Liskov 替换原则?
问题描述
我在尝试理解 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?
我不完全确定,想知道我的假设是否正确
解决方案
子类的行为方式不必与基类相同。它必须实现基类的契约。
不幸的是,您没有记录基类的合同,所以我不能说它是否正确。如果是这样:
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
实现,而且适用于所有有效的子类实现,因为 aProjectTask
是 a Task
。
作为工程师,你的工作就是确保这些承诺得以兑现。
推荐阅读
- postgresql - 如何设置我的 Web 应用程序数据库以在另一台机器上使用 postgres 数据库?
- php - 我将如何创建一个返回数组下一级的函数?
- tomcat - Redisson Tomcat 会话复制唯一 JSESSIONID
- networking - 使用 scapy 回复传入的数据包
- omnet++ - $ParameterName 定义的 INET sink 节点的位置未更新
- neo4j - Neo4j 企业 4.2.9 中未处理的非特定错误
- r - 将多列中的列值更改为 R 中的 NA
- ocr - 如何通过命令行或任何 API 调用 Abbyy Fine reader?
- react-native-contacts - 如何在反应原生联系人中使用添加新功能?
- mysql - 使用 where 和 groupBy 重复检查变慢 - Laravel DB 查询