Java - 违反里氏替换原则?

Java - violation of Liskov substitution principle?

我有以下代码:

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是否违反里氏替换原则?如果是 - 为什么会这样?我在某处读到,我们唯一可以转换为某种类型的时间是当我们知道那将是那种类型时,但编译器不知道。这里我和编译器都不知道。

另一种选择是将 doBeforeRemove 方法移动到 Ops - 但我可能会有很多空方法 - 这对我来说也不合适。

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

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

也就是说,instanceof 是一种“设计味道”。正如@that other guy 所指出的,可以使用 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();
        }
    }
}

如前一个回答所述,这个例子并没有违反里氏替换原则。

但是满足LSP并不是OOP不鼓励instanceof等类型检查的原因。 OOP 最强大的特性是多态性,而类型检查是多态性的对立面。依靠 instanceof 表明 API 并非旨在利用 OOP。您可以重新设计 API 以支持 OOP,但您也可以考虑较少关注多态性的替代编程范例。

综上所述,LSP并不是OOP的首要目标。