我目前正在尝试重构一个看起来像这样的项目的一部分:
许多课程
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用于从每个对象读取(从不写)数据。
答案 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();
如果...
部分差异很大,那么(除了设计有其他问题),你可以看看使用访客模式实现双重调度。