欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

精选枚举代替开关

程序员文章站 2022-05-21 08:19:17
...

问题及其解决方案

开关/案例是用大多数命令式编程语言实现的通用控制结构。 开关比一系列的if / else更具可读性。

这是一个简单的示例:

// Switch with int literal
switch (c) {
  case 1: one(); break;
  case 2: two(); break;
  case 3: three(); break;
  default: throw new UnsupportedOperationException(String.format("Operation %d is not supported", c));
}

这是此代码中的主要问题的列表:

  1. int文字(1、2、3)与执行的代码之间的关系并不明显。
  2. 如果不再支持其中一个值(例如2),并且此开关未相应更新,它将永远包含未使用的代码。
  3. 如果引入了c的新可能值(例如4),并且未相应更新开关,则代码可能会在运行时抛出UnsupportedOperationException而没有任何编译时通知。
  4. 这种开关结构倾向于在代码中重复几次,从而使问题2和3更加复杂。

最简单的解决方法是使用int常量而不是文字。 首先,让我们定义常量:

private static int ONE = 1;
private static int TWO = 2;
private static int THREE = 3;

现在,代码将如下所示:

switch (c) {
  case ONE: one(); break;
  case TWO: two(); break;
  case THREE: three(); break;
  default: throw new UnsupportedOperationException(String.format("Operation %d is not supported", c));
}

(显然,在现实生活中,常量的名称必须是自描述的)

此代码段更具可读性,但所有其他缺点仍然相关。 改进初始代码段的下一个尝试使用2004年在版本5中引入Java语言的enums 。让我们定义以下enum

enum Action {ONE, TWO, THREE}

现在,开关片段将稍作更改:

Action a = ...
switch (a) {
  case ONE: one(); break;
  case TWO: two(); break;
  case THREE: three(); break;
  default: throw new UnsupportedOperationException(String.format("Operation %s is not supported", a));
}

这段代码要好一点:如果从enum Action删除其中一个元素,它将产生编译错误。 但是,如果将其他元素添加到enum Action ,则不会导致编译错误。 在这种情况下,某些IDE或静态代码分析工具可能会产生警告,但是谁在注意警告呢? 幸运的是, enum可以声明必须由每个元素实现的抽象方法:

enum Action {
  ONE { @Override public void action() { } }, 
  TWO { @Override public void action() { } }, 
  THREE { @Override public void action() { } }, 
  public abstract void action();
}

现在,switch语句可以用单行替换:

Action a = ...
a.action();

此解决方案没有上面列举的任何缺点:

  1. 这是可读的。 该方法“附加”到enum元素。 如果方法含义不清楚,则可以编写所需数量的javadoc 调用方法的代码很简单:什么比方法调用更简单?
  2. 在不删除实现的情况下无法删除enum常量,因此,如果某些功能不再相关,则不会保留任何未使用的代码。
  3. 如果没有实现action()方法,则无法添加新的enum元素。 没有实现的代码无法编译。
  4. 如果需要执行多个操作,则可以在枚举中全部执行。 正如我们已经提到的,调用特定功能的代码是微不足道的,因此现在没有代码重复了。

结论

尽管开关/外壳结构是众所周知的,并且以各种编程语言广泛使用,但是其使用可能会引起很多问题。 上面描述的使用Java枚举的解决方案没有这些缺点。 本系列的下一篇文章展示了如何扩展现有enum功能。

翻译自: https://www.javacodegeeks.com/2019/03/featured-enum-instead-switch.html