I am studying liskov substitution principle
. It says sub classes should be proper replacement for the base classes
.
I read an example which I found at various places in the internet. A class Rectangle.java
with height, width
and their setter and getter methods
. A class Square.java
which requires only one attribute i.e length
. If we have Square.java extending Rectangle.java
then this is an violation of this principle. This is because the users of Rectangle.java
expect width
not to get affected if only height
is modified and vice-versa.
My doubts:
The situations we see where methods are just overridden with empty open and close braces in order to prevent the execution of default code written in the base class. Are such cases violation of this principle ?
This principle also says inheritance
should not be used just for reusing the code. Does in case as below it is a bad practice and is this a violation of this principle ?
If a class Window.java is available from some Graphic library. Suppose it has all the code necessary to draw a window. Also suppose it has a toolbar when it is used and drawn. If the requirement is to create a window without toolbar.
Simply Creating a WindowWithoutToolBar.java extending Window.java and overriding the drawToolBarMethod() and leaving it with empty body solves the purpose.[May be just create toolbar and not draw it so as to avoid any exceptions occurring from other methods trying to access toolbar object] Is this a bad practice ?
Creating a whole new Window class without toolbar would have required to rewrite all the code already written in Window.java.
Now if we need AbsoluteNumber.java then in case we extend it from Integer.java does this violates this principle (in case Integer.java has some method as getValueAfterMultiplyByNegativeOne()) ?
Please provide your valuable feedback.
Regards,
Krishna Kumar
Interesting question.
As far as I understand, it would not be
a violation iif leaving the method empty does not change the expected behaviour of that type. Basically, it strengthens the sub-typing requirements by not only respond to "a Square is a Rectangle", but also that its whole interface yields the same behaviour. For instance, what you mentioned about setting a rectangle's width should not affect its height.
Definitely inheritance should not be used only for code re-use. If it actually applies to all possible sub-types, then go ahead, you'll probably be fine. If it only applies to a sub-set of them, you'll find yourself constantly overriding methods and, at the end of the day, writing more code. You can instead encapsulate that common code into meaningful components that can then be used within your classes by means of composition.
In the case of Numbers, I think you're parting from the wrong premise. I would not extend Integer class to implement Naturals. Think when subtracting two naturals, where the second is higher than the first one: ie. 3 - 5. In here, you'd need to make a choice, which would be either to throw an Exception or to return something that is no longer a Natural. A different approach would be to extend an abstract Number class, where you could define a set of methods as follows:
abstract class Number {
public abstract Number sum(Number other);
public abstract Number subtract(Number other);
public abstract Number multiply(Number other);
public abstract Number divide(Number other);
}
This implementation would not be perfect, since it would require some assumptions to be made, like what implicit conversions (casts) to do in case you're operating upon different types. But in this case, it'd allow you to apply the Liskov Substitution principle a bit more freely.