Reputation: 5
I'm having a bit of a hard time trying to understand the Liskov Substitution Principle and was wondering if the following code violates the Liskov Substitution Principle?
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();
}
}
I think it does since the subclass doesn't behave like the base class when it is substituted and also because it throws a RunTimeException?
I'm not entirely sure and was wondering if my assumption was correct
Upvotes: 0
Views: 279
Reputation: 59293
The subclass doesn't have to behave the same way as the base class. It has to implement the base class' contract.
Unfortunately, you didn't document the base class' contract, so I can't say whether or not it is correct. If it's like this:
public class Task {
...
/**
* Attempt to cancel the task.
*
* @throws RuntimeException if the task is not in a cancellable state
*/
public void cancel() {
status = "Closed";
}
}
... then it's just fine.
The contract means that anybody who calls Task.cancel
needs to anticipate an exception.
You see, LSP isn't just about what the base class does, or what the subclass does. It's about the code that uses these things.
LSP says that when a method or constructor is declared to take Task
as an argument, then the declaration promises that it works not just with direct Task
implementations, but all valid subclass implementations, because a ProjectTask
IS a Task
.
Your job as an engineer is to make sure those promises are kept.
Upvotes: 1