Reputation: 31
I wonder how I should organize my two classes.
Knife
: just a simple, solid, basic one, like a kitchen knife.PocketKnife
, which has the state of being opened or closed.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();
}
}
}
None of the classes in my code are abstract.
Does this example violate the LSP?
In my opinion it does, because post-conditions for the cut()
operation should be:
But with the PocketKnife
in its closed state we won't have these post-conditions. Or am I wrong?
Upvotes: 2
Views: 527
Reputation: 3454
Whether it violates LSP or not, depends on what the definition of "cut" IS (not should be). If post-condition for the operation is that the following MUST be true:
Then, PocketKnife does not meet these conditions when "closed". Hence, a PocketKnife cannot be substituted for Knife everywhere and LSP is broken.
How to solve it?
Well, it depends on the context and need more information. But, one example could be this:
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.
}
}
}
With this, LSP will not be broken. Again, the example just gives an idea about ways of tackling such problem.
Upvotes: 1
Reputation: 2307
Liskov Substitution Principle (one of the simplest OOP design guidelines) simply states that any child type must be substitutable for its parent without breaking the program.
If you have a method like someFunc(Knife k) which calls k.cut() and you can pass Knife or Pocketknife or WhateverKnife into that someFunc method and have the program work correctly, then you are not violating LSP.
Upvotes: 0