Java-是否违反Liskov替代原则?

问题描述

我有以下代码

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();
        }
    }
}

是否强制转换BeforeRemove违反了Liskov替代原则?如果是,为什么?我在某处读到,我们唯一可以转换为某种类型的时间是,当我们知道该类型将是该类型时,但是编译器不知道。在这里,我和编译器都不知道。

另一种选择是将dobeforeRemove方法移至Ops-但是可能我会有很多空方法-这在我看来也不对。

解决方法

LSP是指子类和超类(或接口和实现)的行为。它并不涉及用法本身,这意味着您使用这些类的方式与LSP无关,仅涉及类的定义。

因此,您问题中的代码不违反LSP。

也就是说,instanceof是一种“设计气味”。正如@that提到的那样,可以使用Java 8的默认方法将其消除:

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();
        }
    }
}
,

如上一个答案中所述,该示例不违反Liskov替代原则。

但是满足LSP并不是OOP不鼓励诸如instanceof之类的类型检查的原因。 OOP最强大的功能是多态性,而类型检查是多态性的对立面。依靠instanceof表示该API并非旨在利用OOP。您可以重新设计API以支持OOP,但也可以考虑使用其他编程范例,这些范例较少关注多态性。

总而言之,LSP不是OOP的主要目标。