覆盖抽象方法或在枚举中使用单个方法?

Alv*_*ong 14 java enums

考虑下面enums哪个更好?它们都可以完全相同的方式使用,但它们相互之间的优势是什么

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();
}
Run Code Online (Sandbox Code Playgroud)

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 */
}
Run Code Online (Sandbox Code Playgroud)

编辑:我真的希望看到一些很好的理由/精心解答的答案,以及特定声明的证据/来源.由于缺乏证据,大多数关于性能的现有答案并不真正令人信服.

可以建议替代方案,但必须明确它是如何比所陈述的更好和/或所述方法更糟,并在需要时提供证据.

Pau*_*ora 21

忘记这个比较中的表现; 如果两种方法之间存在有意义的性能差异,那将需要一个真正庞大的枚举.

让我们关注可维护性.假设您完成了对Direction枚举的编码并最终转向更有声望的项目.与此同时,另一位开发人员获得了旧代码的所有权,包括Direction- 让我们称他为吉米.

在某些时候,要求要求吉米添加两个新方向:FORWARDBACKWARD.吉米很累,工作过度,并没有费心去全面研究这会如何影响现有的功能 - 他就是这样做的.让我们看看现在发生了什么:

1.覆盖抽象方法:

Jimmy立即得到一个编译器错误(实际上他可能会在enum常量声明下面发现方法覆盖).在任何情况下,都会在编译时发现并修复问题.

2.使用单一方法:

Jimmy没有收到编译器错误,甚至没有得到IDE的错误切换警告,因为你switch已经有了一个default案例.稍后,在运行时,FORWARD.getOpposite()返回一段代码调用null.这会导致意外行为,并且最多会很快导致NullPointerException抛出.

让我们备份并假装你添加一些面向未来的代替:

default:
    throw new UnsupportedOperationException("Unexpected Direction!");
Run Code Online (Sandbox Code Playgroud)

即便如此,直到运行时才会发现问题.希望该项目得到适当的测试!

现在,您的Direction示例非常简单,因此这种情况可能看起来有点夸张.但实际上,枚举可以像其他类一样容易地成为维护问题.在一个更大,更老的代码库中,有多个开发人员对重构的弹性是一个合理的问题.许多人谈论优化代码,但他们可以忘记开发时间也需要优化 - 包括编码以防止错误.

编辑:JLS示例§8.9.2-4下的注释似乎同意:

常量特定的类主体将行为附加到常量.[this]模式比使用switch基类型中的语句更安全...因为模式排除了忘记为新常量添加行为的可能性(因为枚举声明会导致编译时错误).

  • 在你提到它之前,我真的没有想过这个因素!你是对的,因为我的例子*真的*意思是一个简单的例子,但在实践中这确实是一个非常重要的因素.(在接受并授予赏金之前,让我再等几天以获得更多答案......) (3认同)