如果接口无法更改,如何重构此方法



如果不能修改Event接口,如何重构以下方法?PMD报告过于复杂,findbugs报告ITC_INERITANCE_TYPE_CHECKING。还有神奇的数字,比如3、4、5等等

 public int getEventCode(Event event) {
        if (event instanceof OneEvent) {
            return 1;
    }
        if (event instanceof TwoEvent) {
            return 2;
        }
        if (event instanceof ThreeEvent) {
            return 3;
        }
        if (event instanceof FourEvent) {
            return 4;
        }
        if (event instanceof FiveEvent) {
            return 5;
        }
        if (event instanceof SixEvent) {
            return 6;
        }
        if (event instanceof SevenEvent) {
            return 7;
        }
        if (event instanceof EightEvent) {
            return 8;
        }
        if (event instanceof NineEvent) {
            return 9;
        }
        if (event instanceof TenEvent) {
            return 10;
        }
        return event.getClass().hashCode() + 10;
    }

您可以使用List<Class<?>>,例如:

private static final List<Class<? extends Event>> EVENT_CLASSES
    = Arrays.asList(OneEvent.class, ...);

然后:

public int getEventCode(final Event event)
{
    final Class<? extends Event> c = event.getClass();
    final int index = EVENT_CLASSES.indexOf(c);
    return index != -1 ? index + 1 : c.hashCode() + 10;
}

注意:要求事件属于确切的类,而不是派生的(即OneEvent而不是OneDerivedEvent)。否则,测试会稍微复杂一些,但仍然可行。

关于:

findbugs报告ITC_INERITANCE_TYPE_CHECKING

是的,这是因为instanceof检查。

然而:代码中有一个根本性的缺陷不能保证.hashCode()在两个不同的JVM执行之间返回相同的值。此外,允许返回负值。这意味着它可以返回,例如,-4作为一个值;这意味着6将被返回用于"其他事件"并且因此与CCD_ 6冲突。

考虑重构!

public int getEventCode(OneEvent event) {
    return 1;
}
public int getEventCode(TwoEvent event) {
    return 2;
}
// etc.

这并不好,但如果不能更改Event类,这可能是解决需求的最面向对象的方法。这是用多态性替换条件,而不更改有问题的类

代码库中是否有一些类型块浮动?如果是,用多态性替换条件http://refactoring.com/catalog/replaceConditionalWithPolymorphism.html可能会有所帮助。

好吧,使用instanceof是不好的,但如果你甚至不能更改事件接口来添加"int getType()"或类似的东西,至少你可以重组你的代码:

使用"else-if"结构,而不是"just-if"结构。我建议将继承程度更深的事件类型放在第一位,并将更通用的事件声明放在最后(如果测试Event的事件实例,则始终为true)。

这样至少可以降低复杂性。

假设您的所有事件都直接实现事件接口,并且没有其他继承问题需要检查:

public int getEventCode(Event event) {
    int result = event.getClass().hashCode() + 10;
    if (event instanceof OneEvent) {
        result = 1;
    }
    else if (event instanceof TwoEvent) {
        result = 2;
    }
    else if (event instanceof ThreeEvent) {
        result = 3;
    }
    else if (event instanceof FourEvent) {
        result = 4;
    }
    else if (event instanceof FiveEvent) {
        result = 5;
    }
    else if (event instanceof SixEvent) {
        result = 6;
    }
    else if (event instanceof SevenEvent) {
        result = 7;
    }
    else if (event instanceof EightEvent) {
        result = 8;
    }
    else if (event instanceof NineEvent) {
        result = 9;
    }
    else if (event instanceof TenEvent) {
        result = 10;
    }
    return result;
}

我还更改了您的方法,使其只声明一个返回变量,这通常被认为是一种更好的编码实践,因为它也有助于降低复杂性,尽管在这种特殊情况下它没有真正的技术优势。

但正如我所说,如果TenEvent扩展了FiveEvent,您也可能会遇到问题。在这种情况下,我建议使用您收到的事件实例的Class,类似于以下内容:

public int getEventCode(Event event) {
    int result = event.getClass().hashCode() + 10;
    String eventClass = event.getClass().getSimpleName();
    if ("OneEvent".equals(eventClass) {
        result = 1;
    }
    else if ("TwoEvent".equals(eventClass)) {
        result = 2;
    }
    return result;
}

我很懒,只写样本中的前两个,所以你明白了。。。

甚至更好:

public int getEventCode(Event event) {
    int result = event.getClass().hashCode() + 10;
    Class eventClass = event.getClass();
    if (OneEvent.class.equals(eventClass) {
        result = 1;
    }
    else if (TwoEvent.class.equals(eventClass)) {
        result = 2;
    }
    return result;
}