如果不能修改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;
}