将伪方法添加到超类中以便子类可以覆盖它是一种好习惯吗?

时间:2014-09-27 05:20:22

标签: java inheritance arraylist polymorphism override

我有问题。它源于从超类调用子类方法,但有一个扭曲。任何见解将不胜感激。

例如,让我说我有一个子类MultipleChoice,它扩展了一个抽象超类Question。班级MultipleChoice有一个方法addChoice(String choice),而Question会执行任何问题应该做的所有事情,比如显示问题提示,并检查答案是否正确。

我想创建引用MultipleChoice的{​​{1}}实例,然后调用Question方法。这样做的原因是因为我想创建一个问题列表,然后在其中添加不同类型的问题(例如多项选择,真假等)。

这样的事情:

addChoice(String choice)

然而,这当然是一个编译错误,因为不是每个问题都是一个多选问题类型。

我知道两个解决方案。

  1. Typecast:ArrayList<Question> list = new ArrayList(); list.add(new MultipleChoice()); //this is valid list.get(0).addChoice("abc"); list.get(0).addChoice("xyz"); //etc
  2. 将方法((MultipleChoice)list.get(0)).addChoice("abc");添加到超类addChoice(String choice)中,以便Question覆盖它。
  3. 由于我将多次访问MultiplceChoice,因此选项1很难......而选项2似乎真的很糟糕,特别是因为list是抽象的。

    我怎样才能优雅地解决这个问题?

2 个答案:

答案 0 :(得分:3)

您的第二个解决方案没有任何问题。假设使用Java 1.5或更高版本,我会使用泛型。例如:

public abstract class Question<T>
{
  public void addChoice(T newChoice);
}

public class MultipleChoice extends Question<String>
{
  @Override
  public void addChoice(String newChoice)
  {
    // Do whatever you want here
  }
}

您可以将Boolean用于真/假问题。

正如Keale建议的那样,您也可以在将问题添加到列表中之前将所有选项添加到问题 之前。您是否考虑过使用构建器来预先提供所有项目?

如果您尝试不正确地投射某些内容,那么以您建议的第一个解决方案的方式进行类型转换最终可能会导致运行时错误。假设您有以下类型的Question对象列表:

MultipleChoice
MultipleChoice
Boolean
MultipleChoice
Question

循环显示此列表时,您只知道有一个Question对象列表。在尝试强制转换(使用instanceof)之前,您必须检查每个问题的类型,或以某种方式跟踪列表中的哪个项目属于哪种类型。如果您尝试执行(MultipleChoice)list.get(2),请考虑一下会发生什么。

答案 1 :(得分:2)

向超类添加一个仅由一个子类使用的伪方法不是一个好习惯。如果其他人(或将来您)将处理代码并添加将从您的超类Question继承的新类型的问题,这将导致混淆和误解。

您可以将对象添加到列表中,如下所示:

ArrayList<Question> list = new ArrayList<Question>();

MultipleChoice multipleChoiceQ1 = new MultipleChoice();
multipleChoiceQ1.addChoice("abc");

MultipleChoice multipleChoiceQ2 = new MultipleChoice();
multipleChoiceQ2.addChoice("xyz");

list.add(multipleChoiceQ1);
list.add(multipleChoiceQ2);

使用此方法,您可以将其他对象添加到Question的子类列表中,如下所示:

TrueAndFalse trueAndFalse1 = new TrueAndFalse();
//do something here

TrueAndFalse trueAndFalse2 = new TrueAndFalse();
//do something here

list.add(trueAndFalse1);
list.add(trueAndFalse2);

然后在访问列表时使用instanceof检查数据类型。 例如:

for (Question question : list) {
    if (question instanceof MultipleChoice) {
        MultipleChoice multipleChoice = (MultipleChoice) question;
        multipleChoice.doSomething();

    } else if (question instanceof TrueAndFalse) {
        TrueAndFalse trueAndFalse = (TrueAndFalse) question;
        trueAndFalse.doSomethingElse();

    }
}