Java – violation of Liskov substitution principle?

Tags: , , , ,



I have the following code:

interface Ops{
    void remove();
}

interface BeforeRemove{
    void doBeforeRemove();
}

class A implements Ops{
    @Override
    public void remove() {
        System.out.println("REMOVED A");
    }
}

class B implements Ops, BeforeRemove{
    @Override
    public void remove() {
        System.out.println("REMOVED B");
    }

    @Override
    public void doBeforeRemove() {
        System.out.println("SOMETHING TO DO BEFORE REMOVE");
    }
}

public class Proba2 {
    public static void main(String[] args) {
        List<Ops> ops = List.of(new A(), new B());
        for(Ops o : ops){
            if(o instanceof BeforeRemove br){   //is this a bad thing to do?
                br.doBeforeRemove();
            }
            o.remove();
        }
    }
}

Is this cast to BeforeRemove violation of the Liskov substitution principle? If yes – why so? I read somewhere that the only time that we can cast to some type is when we know that that is going to be of that type, but compiler doesn’t know. Here neither I nor the compiler know.

The other alternative would be to move that doBeforeRemove method to Ops – but then possibly I would have a lot of empty methods – that also does not seem right to me.

Answer

LSP refers to the behavior of subclass & superclass (or interface & implementation). It doesn’t refer to the usage itself, meaning that the way you use these classes has no bearing on LSP, only the definition of the classes does.

Therefore, the code in your question does not violate LSP.

That said, instanceof is a “design smell”. As noted by @that other guy, it can be eliminated using Java 8’s default method:

interface Ops {
    void remove();

    default void doBeforeRemove() {}
}

class A implements Ops{
    @Override
    public void remove() {
        System.out.println("REMOVED A");
    }
}

class B implements Ops {
    @Override
    public void remove() {
        System.out.println("REMOVED B");
    }

    @Override
    public void doBeforeRemove() {
        System.out.println("SOMETHING TO DO BEFORE REMOVE");
    }
}

public class Proba2 {
    public static void main(String[] args) {
        List<Ops> ops = List.of(new A(), new B());
        for(Ops o : ops){
            br.doBeforeRemove();
            o.remove();
        }
    }
}


Source: stackoverflow