Java 重构巨大的if(…instanceof…)
我目前正在尝试重构项目的一部分,如下所示: 许多班级Java 重构巨大的if(…instanceof…),java,oop,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 (
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;
...
}...
如果构造当前位于CC为19的函数中,请参见上文。现在我的问题是:我能把这个if构造分解成多个函数,让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}
....
如果:
oopMagic(x);
编辑:我无法更改任何类别(A、B、C等)。在if语句中,一些getter用于从每个对象读取(从不写入)数据。很难说什么最有效,因为您没有给出代码正在执行的任何指示,但另一个选项是添加
oopMagic()
方法到A
并根据需要重写。根据这些中的内容,
您可以在基类中创建虚拟(可能是抽象)方法doMagic
,然后只需:
x.doMagic();
如果
…
部分差异很大,那么(除了在设计上有其他问题外),您可以考虑使用访问者模式实现双重分派。这不会飞instanceof
检测变量的运行时类型。多态性(通过签名选择方法)取决于变量的编译时类型。也就是说,您将始终获得oopMagic(一个obj)
正如罗杰建议的那样,请看一下,也就是双重分派。我担心(正如一位评论者所建议的那样)您只是将问题转移到其他地方,例如,if-else将在其他地方执行。你的方法没有问题,但为了让它更好,你必须做更多的工作
我的建议是创建一个映射,它将根据x的类型处理x。处理器本身是一个通用接口,类似于:
interface Processor<T extends A> {
void oopMagic(T obj);
}
class ProcessorB<B> {
void oopMagic(B obj) { ... }
}
如果您不能更改类的名称,您仍然可以包装它们并引入工厂为您的类型创建正确的包装器:
当然,这不会消除语句的
实例序列,但会将其移动到工厂,这至少是一个更好的地方。工厂方法几乎总是包含一些创建正确对象所需的条件检查。原始作者是怎么想的?@darioo也许“我希望这是支持代数数据类型和模式匹配的Scala”:p@darioo,@pst:或者类似“我就这么干一次”随着时间的推移,子类不断出现。。。接下来……我相信您只是在解决问题,而不是重构它;-)@戈兰:“我会快速而肮脏地完成这一次”->你好,技术债!如果A的每个子类都必须做一些魔术,如果您能够提供默认实现,那么这是最好的解决方案。否则,您可以将您的魔法提取到一个策略中,并为所有应该是魔法的类引入一个新接口;)真的很有趣什么。。。确实如此。
map.get(x.getClass()).oopMagic(x);
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();
// ...