首页 > 解决方案 > 我在这个例子中是否违反了 LSP 原则?

问题描述

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

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并调用它的解锁函数来解锁锁。

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

标签: javaoopdesign-patternssolid-principlesliskov-substitution-principle

解决方案


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

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

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

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
}

推荐阅读