问题描述
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是指子类和超类(或接口和实现)的行为。它并不涉及用法本身,这意味着您使用这些类的方式与LSP无关,仅涉及类的定义。
因此,您问题中的代码不违反LSP。
也就是说,instanceof
是一种“设计气味”。正如@that提到的那样,可以使用Java 8的默认方法将其消除:
interface Ops {
void remove();
default void doBeforeRemove() {}
}
class A implements Ops{
@Override
public void remove() {
System.out.println("REMOVED A");
}
}
class B implements Ops {
@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){
br.doBeforeRemove();
o.remove();
}
}
}
,
如上一个答案中所述,该示例不违反Liskov替代原则。
但是满足LSP并不是OOP不鼓励诸如instanceof
之类的类型检查的原因。 OOP最强大的功能是多态性,而类型检查是多态性的对立面。依靠instanceof
表示该API并非旨在利用OOP。您可以重新设计API以支持OOP,但也可以考虑使用其他编程范例,这些范例较少关注多态性。
总而言之,LSP不是OOP的主要目标。