Reputation: 303
I have the following code
public class A
{
public double foo(double y)
{
return real_value;
}
}
where the input for the foo
method -1 < y < 1
and the result of the function is a real number greater than zero.
Then I have the inherited class B
which inherit the class A
and override the method foo
.
public class B extends A
{
public override double foo(double y)
{
return real_value;
}
}
where the input for the foo
method 0 < y < 1
and the result of the function is any real number.
Is the Liskov Substitution principle violated here?
thanks in advance.
Upvotes: 3
Views: 2423
Reputation: 1167
Assuming, that you want to use B as a subtype of A in your program:
Yes, your code clearly violates LSK.
Why?
Arguments should be contravariant.
What does that mean?
Liskov Principle assures, that your program behaves unchanged if your sub type B is replaced by the base type A.
Or more accurately (by Barbara Liskov, 1987):
“If for each object o1 of type B there is an object o2 of type A
such that for all programs P defined in terms of A, the behaviour of P is unchanged
when o1 is substituted for o2, then B is a subtype of A”.
For example:
class Duck { void fly(int height) {} }
class RedheadDuck : Duck { void fly(long height) {} }
class RubberDuck : Duck { void fly(short height) {} }
class LSPDemo
{
public void Main()
{
Duck p;
p = new Duck();
p.fly(int.MaxValue); // Expected behaviour
p = new RedheadDuck();
p.fly(int.MaxValue); // OK
p = new RubberDuck();
p.fly(int.MaxValue); // Fail
}
}
=> the program behaves unchanged, if the argument is contravariant.
=> e.g. base type <= sub type
=> RubberDuck violates this principle, as it does not allow all values of the base type Duck
In your code the type for the base class A foo would expect argument values -1 < y < 1
Your sub class B foo would expect argument values 0 < y < 1
If your program would replace the sub class with the base class, your program would not behave as expected for foo regarding values <= 0.
EDIT: Although you use double as type for your arguments on both foo methods, I assume that you guard your methods by checking the values and their scope. This would cause the described fail, analogous to the example.
P.S.: Yes it depends on the contract you define for foo. Assuming, that you want to use B as a sub type of A, then it violates the LSK. Otherwise it just a method overriding.
Upvotes: 6
Reputation: 1022
Indeed, your overridden function breaks the contract of base function so the Liskov principle is not really useful here. However, if you add a parameter like "processing mode" to base function, the L-principle works perfectly (overridden function will call base function for all old processing cases).
Upvotes: 0