gpt4 book ai didi

java - 合理 `instanceof` ?将其与接口(interface)一起使用,但不与实现类型一起使用

转载 作者:太空宇宙 更新时间:2023-11-04 09:21:16 28 4
gpt4 key购买 nike

当代码中包含 Java instanceof 运算符时,许多人会扬起眉毛并说这是禁忌。例如,在这个 other SO Q&A ,答案说:

Note that if you have to use that operator very often it is generally a hint that your design has some flaws. So in a well designed application you should have to use that operator as little as possible (of course there are exceptions to that general rule).

但是,它没有进一步详细说明什么时候可以使用 instanceof ,什么时候可以不使用。

我对此进行了一些思考,并阐明了以下指导方针。我认为这可能在互联网上的某个地方讨论过,但我找不到。因此这个问题并征求您的评论:

Using instanceof on an interface is okay; using instanceof on an implementation is not okay

这是“好的”案例的示例。

示例:动物目录,其中一些(但不是全部)可以飞

Animal.java

public interface Animal {
String getName();
String makeNoise();
}

CanFly.java

public interface CanFly {
float getMaxInAirDistanceKm();
}

Cat.java

public class Cat implements Animal {
@Override
public String getName() {
return "Cat";
}

@Override
public String makeNoise() {
return "meow";
}
}

BaldEgale.java

public class BaldEagle implements Animal, CanFly {
@Override
public String getName() {
return "BaldEagle";
}

@Override
public String makeNoise() {
return "whistle";
}

@Override
public float getMaxInAirDistanceKm() {
return 50;
}
}

目录.java

import java.util.ArrayList;
import java.util.List;

public class Catalog {
private List<Animal> animals = new ArrayList<>();

public void putAnimal(Animal animal) {
animals.add(animal);
}

public void showList() {
animals.forEach(animal -> {
StringBuilder sb = new StringBuilder();
sb.append(animal.getName() + ": ");
sb.append(animal.makeNoise() + " ");

// this block exemplifies some processing that is
// specific to CanFly animals
if (animal instanceof CanFly) {
sb.append(String.format(" (can stay in air for %s km)",
((CanFly) animal).getMaxInAirDistanceKm()));
}
System.out.println(sb.toString());
});
}

public static void main(String[] args){

Catalog catalog = new Catalog();
Cat cat = new Cat();
BaldEagle baldEagle = new BaldEagle();
catalog.putAnimal(cat);
catalog.putAnimal(baldEagle);

catalog.showList();
}
}

测试输出

Cat: meow 
BaldEagle: whistle (can stay in air for 50.0 km)

更新于 2019-10-09 添加“不好”案例的示例:

我们可以删除 CanFly 接口(interface),并在 showList() 方法中,将 instanceof 应用于具体实现 BaldEagle ——如下所示:

    public void showList() {
animals.forEach(animal -> {
StringBuilder sb = new StringBuilder();
sb.append(animal.getName() + ": ");
sb.append(animal.makeNoise() + " ");

if (animal instanceof BaldEagle) {
sb.append(String.format(" (can stay in air for %s km)",
((BaldEagle) animal).getMaxInAirDistanceKm()));
}
System.out.println(sb.toString());
});
}

这种方法不好,因为代码现在依赖于实现,而不是接口(interface)。例如,它可以防止替换代表 Bald Eagle 的另一个实现(例如 BaldEagleImpl)

最佳答案

我认为人们认为总有一个“更干净”的解决方案来产生您想要的行为。

在您的示例中,我想说,使用 Visitor 设计模式在不使用 instanceOf 的情况下执行完全相同的操作:

public interface Animal {
String getName();
String makeNoise();
void accept(AnimalVisitor v);
}

public interface AnimalVisitor() {
void visit(Cat a);
void visit(BaldEagle a);
}

public interface CanFly {
float getMaxInAirDistanceKm();
}

public class Cat implements Animal {
void accept(Visitor v) {
v.visit(this);
}
}

public class BaldEagle implements Animal, CanFly {
void accept(Visitor v) {
v.visit(this);
}
}

public class DisplayVisitor implements AnimalVisitor {
void visit(Cat a) {
//build & display your string
}

void visit(BaldEagle a) {
//build & display your string
}
}

public class Catalog {
private List<Animal> animals = new ArrayList<>();

public void putAnimal(Animal animal) {
animals.add(animal);
}

public void showList() {
DisplayVisitor display = new DisplayVisitor();
animals.forEach(a->a.accept(display));
}
}

虽然我没有完全回答你的问题,但它表明在大多数情况下,只需以 OOP 方式思考并使用已知模式,无需使用 instanceOf 即可完成相同的行为。

关于java - 合理 `instanceof` ?将其与接口(interface)一起使用,但不与实现类型一起使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58300819/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com