覆盖抽象方法或在枚举中使用一个单一的方法? [英] Overriding abstract method or using one single method in enums?
问题描述
考虑以下枚举
,哪个更好?他们都可以使用完全相同的方式,但是他们的优势在于彼此?
Consider the below enums
, which is better? Both of them can be used exactly the same way, but what are their advantages over each other?
1。覆盖抽象方法
public enum Direction {
UP {
@Override
public Direction getOppposite() {
return DOWN;
}
@Override
public Direction getRotateClockwise() {
return RIGHT;
}
@Override
public Direction getRotateAnticlockwise() {
return LEFT;
}
},
/* DOWN, LEFT and RIGHT skipped */
;
public abstract Direction getOppposite();
public abstract Direction getRotateClockwise();
public abstract Direction getRotateAnticlockwise();
}
2。使用单一方法:
public enum Orientation {
UP, DOWN, LEFT, RIGHT;
public Orientation getOppposite() {
switch (this) {
case UP:
return DOWN;
case DOWN:
return UP;
case LEFT:
return RIGHT;
case RIGHT:
return LEFT;
default:
return null;
}
}
/* getRotateClockwise and getRotateAnticlockwise skipped */
}
编辑:我真的希望看到一些很好的理由/详细的答案,具体的索赔的证据/来源。由于缺乏证据,大多数关于绩效的现有答案并不真正令人信服。
I really hope to see some well reasoned/elaborated answers, with evidences/sources to particular claims. Most existing answers regarding performance isn't really convincing due to the lack of proves.
您可以提出替代方案,但必须清楚如何更好地说明和/或说明的更糟糕,并在需要时提供证据。
You can suggest alternatives, but it have to be clear how it's better than the ones stated and/or how the stated ones is worse, and provide evidences when needed.
推荐答案
忘记表现在这个比较中;这将需要一个真正庞大的枚举,以便在两种方法之间形成有意义的性能差异。
Forget about performance in this comparison; it would take a truly massive enum for there to be a meaningful performance difference between the two methodologies.
我们将重点放在可维护性上。假设你完成了对 Direction
枚举的编码,并最终进入一个更有声望的项目。同时,另一位开发人员拥有您的旧代码的所有权,包括 Direction
- 让我们称他为Jimmy。
Let's focus instead on maintainability. Suppose you finish coding your Direction
enum and eventually move on to a more prestigious project. Meanwhile, another developer is given ownership of your old code including Direction
- let's call him Jimmy.
,要求规定Jimmy添加了两个新方向: FORWARD
和 BACKWARD
。吉米很累,过度劳累,不用担心会完全研究如何影响现有的功能 - 他只是这样做。让我们看看现在发生了什么:
At some point, requirements dictate that Jimmy add two new directions: FORWARD
and BACKWARD
. Jimmy is tired and overworked and does not bother to fully research how this would affect existing functionality - he just does it. Let's see what happens now:
1。覆盖抽象方法:
Jimmy立即获得编译器错误(实际上他可能会发现方法覆盖在枚举常量声明之下)。在任何情况下,在编译时发现问题。
Jimmy immediately gets a compiler error (actually he probably would've spotted the method overrides right below the enum constant declarations). In any case, the problem is spotted and fixed at compile time.
2。使用单一方法:
Jimmy没有得到编译器错误,甚至没有从他的IDE发出不完整的切换警告,因为您的开关
已经有一个默认值
case。后来,在运行时,某段代码调用 FORWARD.getOpposite()
,返回 null
。这导致意想不到的行为,并且最好 很快就会导致抛出 NullPointerException
。
Jimmy doesn't get a compiler error, or even an incomplete switch warning from his IDE, since your switch
already has a default
case. Later, at runtime, a certain piece of code calls FORWARD.getOpposite()
, which returns null
. This causes unexpected behavior and at best quickly causes a NullPointerException
to be thrown.
让我们备份,并假装你添加了一些未来的打样:
Let's back up and pretend you added some future-proofing instead:
default:
throw new UnsupportedOperationException("Unexpected Direction!");
即使这样,直到运行时才会发现问题。希望项目经过适当测试!
Even then the problem wouldn't be discovered until runtime. Hopefully the project is properly tested!
现在,您的方向
示例很简单,因此这种情况可能会被夸大。在实践中,枚举可以像其他类一样容易地成为维护问题。在较大的较旧的代码库中,具有多个开发人员对重构的抵御力是一个合理的问题。许多人谈论优化代码,但是他们可以忘记开发时间也需要优化 - 包括编码以防止错误。
Now, your Direction
example is pretty simple so this scenario might seem exaggerated. In practice though, enums can grow into a maintenance problem as easily as other classes. In a larger, older code base with multiple developers resilience to refactoring is a legitimate concern. Many people talk about optimizing code but they can forget that dev time needs to be optimized too - and that includes coding to prevent mistakes.
编辑: JLS示例§下的注释8.9.2-4 似乎同意:
常量特定的类体向常量附加行为。 [这个]模式比在基本类型中使用
开关
语句更安全,因为该模式排除了遗忘为新常量添加行为的可能性(因为枚举声明会导致编译时错误)。
Constant-specific class bodies attach behaviors to the constants. [This] pattern is much safer than using a
switch
statement in the base type... as the pattern precludes the possibility of forgetting to add a behavior for a new constant (since the enum declaration would cause a compile-time error).
这篇关于覆盖抽象方法或在枚举中使用一个单一的方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!