0

我的程序中有以下课程:

public abstract class Question {

    private Topic topic;
    private String text;

    // methods

}

public class OpenQuestion extends Question {

    // methods

}

public class MultipleChoiceQuestion extends Question {

    private List<String> options = new ArrayList<String>();
    private String correct;

    // methods

}

此外,我还有另一个类测试:

Question question;

// if the question is open

    if(question instanceof OpenQuestion) {

    ...

    }

// if the question is multiple choice

    if(question instanceof MultipleChoiceQuestion) {

    ...

    }

我正在尝试寻找替代方案instanceof,因为有人告诉我它违反了 OOP 原则。

还有其他更好的方法可以知道问题是开放式还是多项选择?

4

4 回答 4

4

关键字本身并instanceof没有违反 OOP 原则。他们可能意味着您应该使用多态性来执行逻辑。

代替:

if(question instanceof OpenQuestion) {

...
}

//Countless ifs

if(question instanceof MultipleChoiceQuestion) {
...

}

你应该

question.doAction();

另一个例子(更明确):

abstract class Animal{
    public abstract void speak();
}

class Dog extends Animal{
    public void speak(){ System.out.println("Bark!"); }
}

class Cat extends Animal{
    public void speak(){ System.out.println("Meow!"); }
}
于 2013-05-15T00:05:24.870 回答
0

当然你可以看到这个例子:

import java.lang.reflect.*;
import java.awt.*;

class SampleName {

public static void main(String[] args) {
Button b = new Button();
printName(b);
}

static void printName(Object o) {
   Class c = o.getClass();
   String s = c.getName();
   System.out.println(s);
}
}
于 2013-05-15T00:04:08.787 回答
0

破坏 OOP 的不是 instanceof 本身,而是知道您的类是哪个特定类的实例,从而破坏了它。

如果您的课程是“动物”,可以是狗、猫或鸟...... Animal.legs() 应该足以在不知道动物类型的情况下计算腿——这当然是简单的情况。更难的情况是当一些动物的方法对其他人没有意义时。

以不适用于狗或猫的 fly() 为例。在这种情况下,有一些解决方案,奇怪的是在这种情况下 instanceof 可能是最好的一个!

您可以: 仅在bird 上实现 fly() 并反射以查看 Bird 是否具有 fly() 方法。在每个类上实现 canFly() 和 fly(),如果不能,让 fly() 抛出异常。

这些都不是好的——根本不是面向对象,丑陋和无缘无故重复(如果你有可用的鸭子打字,第一个还不错,但即使那样它也不是最明显的解决方案)

那么什么是好的解决方案?有一个声明 fly() 方法的“Flies”接口,并且只有“Bird”实现了 Flies。在这种情况下,instanceof 是一个很好的解决方案——可能是最好的!

不好:if(animal instancef Bird) ((Bird)animal).fly()

好: if(animal instanceof Flies) ((Flies)animal).fly()

这是一个非常微妙的区别,直到你明白为什么——当你添加蝙蝠时会发生什么?在第一个中,您拥有:

if(animal instancef Bird)
    ((Bird)animal).fly()
else if(animal instancef Bat)
    ((Bat)animal).fly()

这是一个开关、构造,任何时候你发现自己用 OO 语言编写开关构造,你可能做错了什么(这就是他们说 instanceof 错误的原因,因为它会导致开关构造)

只要 Bat 实现 Flies,第二个示例仍然保持不变,并将继续为您实现的任何新对象。这是了不起的。

以这种方式使用接口比鸭子类型和反射具有优势——因为它是特定的和经过深思熟虑的。你不会不小心在 Pants 对象上调用 .fly() 并得到一个你没想到的 Zipper,你可以检查“bat”的代码并轻松理解其意图。

于 2013-05-15T00:32:32.637 回答
0

如果您对 OO 设计感兴趣,请考虑是否可以执行以下操作:让 Question 类有一个可以调用的方法,而不是 if 语句中的代码

public abstract class Question {
    private Topic topic;
    private String text;
    // methods
    public void abstract doSomething(Object arg);
}

public class OpenQuestion extends Question {
    @Override
    public void doSomething(Object arg) {
        // do something with an open question
    }
    // other methods
}

public class MultipleChoiceQuestion extends Question {
    private List<String> options = new ArrayList<String>();
    private String correct;
    @Override
    public void doSomething(Object arg) {
        // do something with an open question
    }
    // other methods
}

另一个类中的代码是:

Question question;
question.doSomething(arg);

do something 中的参数是为了传递 Question 对象不知道的任何信息,但是当你想做某事时你就有了它。

于 2013-05-15T00:12:23.900 回答