Java 面向对象设计-何时使用getClass和instanceof
在大学演讲中,讲师说使用Java 面向对象设计-何时使用getClass和instanceof,java,oop,Java,Oop,在大学演讲中,讲师说使用getClass和instanceof表示设计不好 哪些是糟糕设计的示例用法?使用这些方法会导致哪些问题?这些方法是否有任何有效的用途,这些都是不错的设计?糟糕的用途 我想说的是,在大多数情况下,这是糟糕设计的标志。例如,假设您有一个对象列表,您正在执行instanceof,然后是cast,然后是调用特定于该类的方法。相反,这些对象应该具有公共超类,并且应该在其中声明方法——然后根据对象的实际类型执行不同的代码(因为子类可能定义不同的实现) 使用反射API的工具 使用这些
getClass
和instanceof
表示设计不好
哪些是糟糕设计的示例用法?使用这些方法会导致哪些问题?这些方法是否有任何有效的用途,这些都是不错的设计?糟糕的用途
我想说的是,在大多数情况下,这是糟糕设计的标志。例如,假设您有一个对象列表,您正在执行instanceof
,然后是cast,然后是调用特定于该类的方法。相反,这些对象应该具有公共超类,并且应该在其中声明方法——然后根据对象的实际类型执行不同的代码(因为子类可能定义不同的实现)
使用反射API的工具
使用这些方法的另一个有效案例是创建各种工具(如POJO到json映射器)时,这只能通过反射API完成
编辑:
根据您在评论中提出的问题,以下是如何实现动物列表的工作示例,其中狗可以奔跑,鹰可以奔跑和飞翔:
public static abstract class Animal {
protected final String name;
public Animal(String name) {
this.name = name;
}
public void run() {
System.out.println(name + " runs");
}
public abstract void move();
}
public static class Dog extends Animal {
public Dog() {
super("Dog");
}
@Override
public void move() {
run();
}
}
public static class Eagle extends Animal {
public Eagle() {
super("Eagle");
}
public void fly() {
System.out.println(name + " flies");
}
@Override
public void move() {
fly();
}
}
public static void main(String[] args) {
List<Animal> animals = Arrays.asList(new Dog(), new Eagle());
animals.forEach(Animal::move);
System.out.println("Eagle can run too!");
new Eagle().run();
}
这一切都是关于如何分析代码的使用和提取公共部分。如果在循环中您总是命令动物跑步,则不需要强制转换,因为
run()
是在animal
上声明的。另一方面,在这里,我们希望动物移动,而不管如何移动,所以让它们通过在animal
类中创建抽象的move()
方法来选择默认的移动类型。通常在设计良好的代码中,您不需要这样做。最常见的情况是,这是因为您与无法更改的对象交互,但需要基于这些对象具有不同的行为
例如,如果Jaroslaw Pawlak示例中的动物是由第三方库提供的,您无法更改,现在需要添加新的行为(例如,腿部受伤的动物不再能跑,但可以飞),那么使用instanceof可能是实现这一点的唯一方法
结果往往是糟糕的架构,在理想世界中你不会这样做,但有时这是获得所需结果的唯一途径
我也在Swing GUI中使用过它,例如,我在JPanel中有许多不同的控件,我正在扫描列表并根据控件的类型调用不同的方法。另一种方法是保存特定类型控件的列表和/或编写包装并保存这些包装的列表。这两种方法都会增加更多的簿记和开销,并且确保列表始终同步可能会在将来导致奇怪的错误(例如,如果您添加了一个控件,但忘记将其添加到要扫描的列表中)。每个重载的equals()方法都使用instanceOf或getClass,所以我不认为使用这些是一个糟糕的设计。@EdwinJarosiński我想不出更多的有效案例。我见过很多代码,其中在多个if语句中使用了
instanceof
,根据输入参数等决定要执行的代码。这是一个糟糕的设计。嗯。。。在其他情况下这是正确的,这是糟糕的设计。我不想遇到像检查输入参数这样的人,这是一个很好的答案!非常感谢:)在以下情况下可以避免它:Animal是一个抽象类,具有以下字段:name、groundSpeed和run作为抽象方法。我们有狗类有相同的字段和运行方法。除此之外,我们还有鹰类,也有飞行速度场。Eagle有一个run method和fly method的实现。@Niminim这一切都取决于您实际如何使用这些对象。@Niminim所以即使Eagle既能跑又能飞,您也不能让它跑,而是让它飞。这意味着您可以在Animal
中创建move
方法-Dog
将其委托给run
,而Eagle
将其委托给fly
。然后你只需对动物调用move
,不管它到底是什么动物。在编写时,我实际上没有考虑在move()
中添加逻辑:)很高兴我能提供帮助。关于外部库的观点很好。为了给您提供另一个真实的示例,我最近使用了NetSuite的SuiteTalk,一个SOAP web服务API。从概念上讲,它有一个事务类,其中包含子类Invoice、CustomerRefund、CashDeposit等,但它们在Java类定义中实际上并不相关。它们都有常用的方法,例如getTranId()。要编写一个接受任何事务类型并打印其事务id的方法,需要使用反射,因为您不能以多态方式调用getTranId()。谢谢Tim和klitos!我还没有使用过任何第三方库,但我相信这一见解在将来会更加相关。
private interface Printer {
void print();
}
private static class A implements Printer {
@Override
public void print() {
System.out.println("A");
}
}
private static class B implements Printer {
@Override
public void print() {
System.out.println("B");
}
}
public static void main(String[] args) {
List<Printer> list = asList(new A(), new B(), new A());
list.forEach(Printer::print);
}
public class Person {
private String name;
private String surname;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
if (!name.equals(person.name)) return false;
return surname.equals(person.surname);
}
}
public static abstract class Animal {
protected final String name;
public Animal(String name) {
this.name = name;
}
public void run() {
System.out.println(name + " runs");
}
public abstract void move();
}
public static class Dog extends Animal {
public Dog() {
super("Dog");
}
@Override
public void move() {
run();
}
}
public static class Eagle extends Animal {
public Eagle() {
super("Eagle");
}
public void fly() {
System.out.println(name + " flies");
}
@Override
public void move() {
fly();
}
}
public static void main(String[] args) {
List<Animal> animals = Arrays.asList(new Dog(), new Eagle());
animals.forEach(Animal::move);
System.out.println("Eagle can run too!");
new Eagle().run();
}
Dog runs
Eagle flies
Eagle can run too!
Eagle runs