【发布时间】:2020-11-08 22:45:05
【问题描述】:
我有以下代码:
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 是否违反了 Liskov 替换原则?如果是 - 为什么会这样?我在某处读到,我们可以强制转换为某种类型的唯一时间是当我们知道那将是那种类型但编译器不知道时。这里我和编译器都不知道。
另一种选择是将 doBeforeRemove 方法移动到 Ops - 但是我可能会有很多空方法 - 这对我来说似乎也不合适。
【问题讨论】:
-
在这种情况下,您没有做任何违反 LSP 的事情。但是,如果一个对象突然需要在
remove()之前调用doBeforeRemove(),那么以后很容易导致违规,即使Ops说如果没有这样的调用,该对象应该是可移除的。您是否考虑过在您的界面中使用default方法? -
我的意思是,理论上大多数 OOP 方法是使用访问者模式,并为
Ops, BeforeRemove和Ops提供不同的实现,但这会使事情变得有点复杂。我只是想问一下instanceof,因为我读到它是使用 OOP 时的代码异味。 -
如果
B extends A implements BeforeRemove和 B 的remove()需要首先调用doBeforeRemove(),那么它违反了 LSP,因为它不能再代表 A。但是,现在它只是一个代码味道而不是 LSP 违规。我肯定会说空方法是一种更清洁、更合适的方法。这并不难看或乏味,因为自 Java 8 以来您不必实际编写未使用的方法,甚至在此之前,您有抽象类来简化它。 -
@BojanVukasovic 请问这里为什么需要
doBeforeRemove?Ops实现者将知道何时已经调用了remove,客户端也是如此。你想解决什么问题?拥有这两个操作会迫使客户知道应该以什么顺序调用它们,这不是很吸引人。 -
@plalx 是的,我猜这里
doBeforeRemove应该隐藏在remove后面。我记得instanceof是一种代码异味,这更像是一个问题,但后来想看看在这种情况下可以做什么——比如添加基本空方法的替代方法,这也不理想......
标签: java oop design-patterns solid-principles liskov-substitution-principle