重构如果(... instanceof ...)

时间:2010-12-22 07:50:38

标签: java oop

我目前正在尝试重构一个看起来像这样的项目的一部分:

许多课程

 B extends A; C extends A; D extends C; E extends B; F extends A; ...

代码中的某处:

if (x instanceof B){
 B n = (B) x;
 ...
}else if (x instanceof C){
 C n = (C) x;
 ...
}else if (x instanceof D){
 D n = (D) x;
 ...
}else if (x instanceof E){
 E n = (E) x;
 ...
}else if (x instanceof G){
 G n = (G) x;
 ...
}...

上面的if-construct目前位于一个CC为19的函数中。现在我的问题是:我可以在mutliple函数中拆分这个if-construct并让Java的OO做出魔术吗?或者我有什么需要注意的东西吗?

我的想法:

private void oopMagic(C obj){ ... Do the stuff from the if(x instanceof C) here}
private void oopMagic(D obj){ ... Do the stuff from the if(x instanceof D) here}
private void oopMagic(E obj){ ... Do the stuff from the if(x instanceof E) here}
....

而不是巨大的if:

oopMagic(x);

编辑:我无法更改任何类(A,B,C,...)。在if语句中,一些getter用于从每个对象读取(从不写)数据。

5 个答案:

答案 0 :(得分:5)

那不会飞。 instanceof检测变量的运行时类型。多态性(通过签名选择方法)取决于变量的编译时类型。也就是说,你总是得到oopMagic(A obj)

正如罗杰建议的那样,看看visitor pattern,a.k.a双重发送。

答案 1 :(得分:2)

很难说出哪些方法最有效,因为您没有给出代码正在做什么的任何指示,但另一个选择是向oopMagic()添加A方法并在必要时覆盖。< / p>

答案 2 :(得分:2)

如果您无法更改类,您仍然可以包装它们并引入工厂来为您的类型创建正确的包装器:


public interface Wrapper {
  public void magicMethod();  // you know what I mean
}

public AWrapper implements Wrapper {
  private A a;
  public AWrapper(A a){this.a=a;};

  @Override
  public void magicMethod() {
    // do what has to be done with a
  }
}

public Factory {
  public static createWrapper(Object wrappable) {
    if (wrappable instanceof A)
        return new AWrapper((A) wrappable);
    // ...
  }
}

// ...
Object x = getXFromSomewhere();
Wrapper wrapper = Factory.getWrapper(x);
wrapper.magicMethod();
// ...

当然,这不会消除instanceof陈述的顺序,但它会把它移到工厂,这至少是一个更好的地方。工厂方法几乎总是包含一些创建正确对象所需的条件检查。

答案 3 :(得分:1)

我害怕(正如一位评论者所建议的那样)你只是将问题转移到其他地方,例如if-else将在其他地方完成。您的方法没有问题,但要做得更好,您还需要做更多的工作。

我建议创建一个将根据其类型处理x的Map。处理器本身是一个通用接口,如:

interface Processor<T extends A> {
     void oopMagic(T obj);
}

然后为每个类创建处理器的实现,例如:

class ProcessorB<B> {
     void oopMagic(B obj) { ... }
}

将所有实现类放在地图中,然后执行:

map.get(x.getClass()).oopMagic(x);

答案 4 :(得分:0)

根据...中的内容,您可以在基类中创建虚拟(可能是抽象的)方法doMagic,然后只需:

x.doMagic();

如果...部分差异很大,那么(除了设计有其他问题),你可以看看使用访客模式实现双重调度。