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

当代码中包含 Javainstanceof操作符时,很多人都会皱起眉头并说这是禁忌。例如:

请注意,如果您必须经常使用该运算符,通常表明您的设计存在一些缺陷。因此,在设计良好的应用程序中,您应该尽可能少地使用该运算符(当然,该一般规则也有例外)。

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

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

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

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

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

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;

    }

}

Catalog.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());

        });

    }


DIEA
浏览 112回答 3
3回答

鸿蒙传说

我认为人们认为总是有一个“更干净”的解决方案来产生你想要的行为。在您的示例中,我想说,使用 Visitor 设计模式在不使用 instanceOf 的情况下执行完全相同的操作:public interface Animal {&nbsp; &nbsp; String getName();&nbsp; &nbsp; String makeNoise();&nbsp; &nbsp; void accept(AnimalVisitor v);}public interface AnimalVisitor() {&nbsp; &nbsp; void visit(Cat a);&nbsp; &nbsp; void visit(BaldEagle a);}public interface CanFly {&nbsp; &nbsp; float getMaxInAirDistanceKm();}public class Cat implements Animal {&nbsp; &nbsp; void accept(Visitor v) {&nbsp; &nbsp; &nbsp; &nbsp; v.visit(this);&nbsp; &nbsp; }}public class BaldEagle implements Animal, CanFly {&nbsp; &nbsp; void accept(Visitor v) {&nbsp; &nbsp; &nbsp; &nbsp; v.visit(this);&nbsp; &nbsp; }}public class DisplayVisitor implements AnimalVisitor&nbsp; {&nbsp; &nbsp; void visit(Cat a) {&nbsp; &nbsp; &nbsp; &nbsp;//build & display your string&nbsp; &nbsp; }&nbsp; &nbsp; void visit(BaldEagle a) {&nbsp; &nbsp; &nbsp; &nbsp;//build & display your string&nbsp; &nbsp; }}public class Catalog {&nbsp; &nbsp; private List<Animal> animals = new ArrayList<>();&nbsp; &nbsp; public void putAnimal(Animal animal) {&nbsp; &nbsp; &nbsp; &nbsp; animals.add(animal);&nbsp; &nbsp; }&nbsp; &nbsp; public void showList() {&nbsp; &nbsp; &nbsp; &nbsp; DisplayVisitor display = new DisplayVisitor();&nbsp; &nbsp; &nbsp; &nbsp; animals.forEach(a->a.accept(display));&nbsp; &nbsp; }}instanceOf虽然我没有完全回答你的问题,但它表明在大多数情况下,只需以 OOP 方式思考并使用已知模式即可完成相同的行为,而无需使用。

子衿沉夜

首先,需要注意的是,面向对象编程范式是抵制类型检查(例如instanceof.&nbsp;其他范例不一定有这种阻力,甚至可能鼓励类型检查。所以这个问题只有在你尝试进行 OOP 时才有意义。如果您尝试进行 OOP,那么您应该尽可能多地利用多态性。多态性是 OOP 的主要武器。类型检查是多态性的对立面。当然,抽象的类型检查优于具体实现的类型检查;但这只是重申依赖倒置原则(依赖于抽象,而不是具体)。在 OOP 中,每次使用类型检查都可以被视为错失了多态性的机会。

白衣染霜花

不过具体什么时候使用还可以就不再详细说明instanceof了这不是对您问题的直接回答,但我想说,instanceof只有当所有其他选项都不可行时,这才合适。instanceof在接口上使用是可以的;instanceof在实现上使用是不行的我将其重新表述为“instanceof在接口上使用比在实现上使用要好instanceof”,但这只是强耦合不好这一一般规则的推论。通常有更好的选择。当你想使用时instanceof,你应该首先考虑引入额外的接口或接口方法或使用访问者模式。所有这些选项都是在 Java 中实现所需行为的更简洁的方法。这并不总是优雅的,并且可能需要人工接口或导致接口膨胀,这就是为什么其他一些语言支持临时联合类型和代数数据类型的原因。但这instanceof都不是一个好的模拟方法,因为 Java 的类型系统无法帮助您确保处理所有可能的选项。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java