为了账号安全,请及时绑定邮箱和手机立即绑定

合理的“实例”?将其与接口一起使用,但不与实现类型一起使用

合理的“实例”?将其与接口一起使用,但不与实现类型一起使用

DIEA 2023-10-12 17:13:21
当代码中包含 Javainstanceof操作符时,很多人都会皱起眉头并说这是禁忌。例如:请注意,如果您必须经常使用该运算符,通常表明您的设计存在一些缺陷。因此,在设计良好的应用程序中,您应该尽可能少地使用该运算符(当然,该一般规则也有例外)。不过,没有进一步详细说明什么时候可以使用instanceof,什么时候不行。我对此进行了一些思考,并阐明了以下指导方针。我认为这可能在互联网上的某个地方讨论过,但我找不到。因此这个问题并征求您的评论:instanceof在接口上使用是可以的;instanceof在实现上使用是不行的这是&ldquo;好的&rdquo;案例的示例。示例:动物目录,其中一些(但不是全部)可以飞Animal.javapublic interface Animal {    String getName();    String makeNoise();}CanFly.javapublic interface CanFly {    float getMaxInAirDistanceKm();}Cat.javapublic class Cat implements Animal {    @Override    public String getName() {        return "Cat";    }    @Override    public String makeNoise() {        return "meow";    }}BaldEgale.javapublic class BaldEagle implements Animal, CanFly {    @Override    public String getName() {        return "BaldEagle";    }    @Override    public String makeNoise() {        return "whistle";    }    @Override    public float getMaxInAirDistanceKm() {        return 50;    }}Catalog.javaimport 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());        });    }
查看完整描述

3 回答

?
鸿蒙传说

TA贡献1865条经验 获得超7个赞

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


在您的示例中,我想说,使用 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));

    }

}

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


查看完整回答
反对 回复 2023-10-12
?
子衿沉夜

TA贡献1828条经验 获得超3个赞

首先,需要注意的是,面向对象编程范式是抵制类型检查(例如instanceof. 其他范例不一定有这种阻力,甚至可能鼓励类型检查。所以这个问题只有在你尝试进行 OOP 时才有意义。

如果您尝试进行 OOP,那么您应该尽可能多地利用多态性。多态性是 OOP 的主要武器。类型检查是多态性的对立面。

当然,抽象的类型检查优于具体实现的类型检查;但这只是重申依赖倒置原则(依赖于抽象,而不是具体)。

在 OOP 中,每次使用类型检查都可以被视为错失了多态性的机会。


查看完整回答
反对 回复 2023-10-12
?
白衣染霜花

TA贡献1796条经验 获得超10个赞

不过具体什么时候使用还可以就不再详细说明instanceof

这不是对您问题的直接回答,但我想说,instanceof只有当所有其他选项都不可行时,这才合适。

instanceof在接口上使用是可以的;instanceof在实现上使用是不行的

我将其重新表述为“instanceof在接口上使用比在实现上使用要好instanceof”,但这只是强耦合不好这一一般规则的推论。通常有更好的选择。

当你想使用时instanceof,你应该首先考虑引入额外的接口或接口方法或使用访问者模式。所有这些选项都是在 Java 中实现所需行为的更简洁的方法。

这并不总是优雅的,并且可能需要人工接口或导致接口膨胀,这就是为什么其他一些语言支持临时联合类型和代数数据类型的原因。但这instanceof都不是一个好的模拟方法,因为 Java 的类型系统无法帮助您确保处理所有可能的选项。


查看完整回答
反对 回复 2023-10-12
  • 3 回答
  • 0 关注
  • 99 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信