Java 在这个例子中,我是否违反了LSP原则?
我的代码实现了两种类型的门。 一扇门有锁,另一扇门没有 门界面非常简单:Java 在这个例子中,我是否违反了LSP原则?,java,oop,design-patterns,solid-principles,liskov-substitution-principle,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 voi
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替代原则?如果是,那么什么是一个好的选择?回答这个问题有点困难,因为您的
门的接口似乎不完整,因为不清楚打开()
和关闭()
应该做什么。让我们添加一个isOpen()
方法,并定义一旦调用open()
,对isOpen()
的后续调用应该返回true
(为了简洁起见,我故意忽略了如果您试图打开并且已经打开门会发生什么的问题)
在这种情况下,你肯定违反了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
}
不,您(可能)没有违反LSP
更长的回答:当然取决于您对界面门中的open()
方法的“定义”。如果您将该方法定义为“如果可能,尝试打开门”,则您处于清除状态
有人可能会争辩说,应该调用open()
方法tryOpen()
,以向调用方阐明您的意图,即调用后门可能不会打开
但是,如果您定义了open()
方法来始终打开门,那么您当然违反了LockedDoor
中的合同(和LSP)
另一个问题是,接口中缺少一些东西。目前,打开/关闭状态对任何可用方法都没有影响open()
/close()
。我假设您在门中有一些与门的状态相关的其他方法,例如漫游()
或类似的方法。您的问题在这里更合适:为什么您认为需要两个不同的类?一门课不够吗?你只需要检查isOpen
状态,如果门被锁或没有锁:)@KarelG在引用其他站点时,我认为最好是在无法打开时使open()抛出异常。通过使用命令方法的返回值,您可以中断CQS,尽管区分成功和失败的open()执行仍然有好处。异常清楚地表明,要么命令成功,要么我们应该转到不同的执行流。