This article prompted me to reflect: http://blog.byndyu.ru/2009/10/blog-post_29.html Let me give you a slightly revised example from it:
public interface IList { public void add(int e); } public class List implements IList{ @Override public void add(int e) { // добавляет элемент } } public class DoubleList implements IList{ @Override public void add(int e) { // добавляет элемент // добавляет элемент } }
The add method in the DoubleList class adds an element twice. In the client code, you can write something like this:
public void LSPTest(IList list){ int oldLen = list.getLength(); list.add(1); int newLen = list.getLength(); if(newLen - oldLen == 1){ // делать что то полезное } }
It is obvious that the behavior of the program will be different, depending on whether the LSPTest
function LSPTest
an object of the List
or DoubleList
. But does it break the LSP? After all, DoubleList
does not inherit the List
class, but the IList
interface. The interface cannot set any preconditions and postconditions (in this case it does not specify exactly). And the interfaces are written in order to have different implementations, sometimes having very little in common. I have always believed that if, for example, DoubleList
were inherited from List
, then selecting the interface and lowering classes one level is just the solution to a problem when an LSP is violated. In my opinion this is called factorization. And besides, the LSP says that the program should not change if instead of the base class object we substitute the derived object. But how can you substitute something instead of an object of the base class, if the base class is abstract? Or even more interface? Instead, you can not substitute anything, because it simply can not be created.
length()
method of yourIList
and writing to it and toadd( int e )
javadoc. What you write there will be the expected behavior, and it is these expectations that the implementing objects must meet. - zRrr