我是否在此示例中违反了LSP原则?

时间:2018-04-26 06:17:39

标签: java oop design-patterns solid-principles liskov-substitution-principle

我有这个代码实现了两种类型的门。 一扇门包含锁,另一扇门没有。

界面毫无疑问:

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

然后我有实施: LockedDoor RegularDoor

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接收锁定并调用它的解锁功能来解锁。

是否违反Liskov替代原则?
如果是的话,什么是一个好的选择?

2 个答案:

答案 0 :(得分:2)

有点难以回答这个问题,因为Door的界面似乎不完整,因为它不清楚open()close()是什么意思去做。让我们通过添加isOpen()方法清除它,并定义一旦调用open(),后续调用isOpen()应该返回true(和我&# 39;如果你试图打开并且已经打开门,为了简洁起见,故意忽略了会发生什么的问题。

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

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

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
}

答案 1 :(得分:1)

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

更长的答案:当然取决于界面open()Door方法的“定义”。如果您将方法定义为“尝试打开门,如果可能”,那么您就是明确的。

可能有人认为应该调用open()方法tryOpen()来澄清你打电话给呼叫后门可能没有打开的意图。

但是,如果您将<{1}}方法定义为总是打开门,那么您当然违反了open()中的合同(和LSP)。

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