我在这个例子中是否违反了 LSP 原则?

Did I violate the LSP principle in this example?

我有实现 2 种门的代码。 一扇门有锁,另一扇没有。

Door 界面很简单:

public interface Door {
    void open();
    void close();
}

然后我有实现:LockedDoorRegularDoor

public class LockedDoor implements Door {
    private Lock lock;
    private boolean isOpen;

    @Override
    public void open() {
        if(!lock.isLocked()) {
            this.isOpen = true;
        }
    }

    @Override
    public void close() {
        this.isOpen = false;
    }
}

public class RegularDoor implements Door {
    private boolean isOpen;

    @Override
    public void open() {
        isOpen = true;
    }

    @Override
    public void close() {
        isOpen = false;
    }
}

如您所见,LockedDoor的开门功能只有在锁打开时才会开门。
您可以通过从 LockedDoor 接收锁并调用它的解锁函数来解锁锁。

是否违反里氏替换原则?
如果是,什么是好的选择?

回答这个问题有点困难,因为您的 Door 界面似乎不完整,因为不清楚 open()close() 应该做什么。让我们通过添加一个 isOpen() 方法来清除它,并定义一旦 open() 被调用,对 isOpen() 的后续调用应该 return true (我'为了简洁起见,我故意忽略了如果您尝试打开并且已经打开的门会发生什么的问题。

在这种情况下,你肯定违反了 LSP 原则 - 如果你试图打开一扇锁着的门,你会失败,而且门会保持关闭状态。

解决此问题的一种方法是向 open()close() 方法添加一个 return 值,以便它们可以报告操作是否成功:

public interface Door {
    /**
     * Checks if the door is open.
     * @return {@code true} if the door is open, {@code false} if not.
    boolean isOpen();

    /**
     * Attempt to open the door.
     * @return {@code true} if the door was successfully opened, 
     * {@code false} if not.
     * In other words, if a call to {@code open} returns {@code true}, a
     * subsequent call to {@link #isOpen} will return {@code true}.
     */
    boolean open();

    /**
     * Attempt to close the door.
     * @return {@code true} if the door was successfully closed, 
     * {@code false} if not.
     * In other words, if a call to {@code close} returns {@code true}, a
     * subsequent call to {@link #isOpen} will return {@code false}.
     */
    void close();
}

public class RegularDoor implements Door {
    private boolean isOpen;

    @Override
    public boolean isOpen() {
        return isOpen;
    }

    @Override
    public boolean open() {
        return isOpen = true;
    }

    @Override
    public boolean close() {
        return isOpen = false;
    }
}


public class LockedDoor implements Door {
    private Lock lock;
    private boolean isOpen;

    @Override
    public boolean isOpen() {
        return isOpen;
    }

    @Override
    public boolean open() {
        if (!lock.isLocked()) {
            return isOpen = true;
        }
        return false;
    }

    @Override
    public boolean close() {
        return isOpen = false;
    }

    // Not shown here - methods to lock and unlock the door
}

,您(可能)没有违反 LSP。

更长的答案:当然取决于接口 Dooropen() 方法的 "definition"。如果您将方法定义为“尝试在可能的情况下打开门”,那么您就没有问题了。

可能有人认为应该调用 open() 方法 tryOpen() 以向调用者阐明您的意图,即调用后门可能不会打开。

如果您将 open() 方法定义为 总是 打开门,那么您当然违反了 LockedDoor 中的合同(和 LSP) .

另一个问题是,界面中缺少一些东西。就目前而言,open/closed 状态对任何可用方法 open()/close() 没有 效果 。我假设您在 Door 中有一些其他方法与门的状态相关,例如 walkThrough() 或类似的方法。