5

假设一个方法根据一个相当大的枚举中的一个值来选择一个动作。我们的声纳现在抱怨这种方法的圈复杂度很高(自然是关于 case 语句的数量)。

我知道,大型 switch case 语句并不是 OOP 中的最佳风格,但有时使用它们(在我的例子中是评估运算符标记的解析器)而不是构建复杂的对象树是非常合适的。

我现在的担心是怎么处理的?是否有任何设计模式可以有意义地拆分这样的开关盒?或者我可以(并且我应该)将课程排除在测量 CC 之外(因为其中可能有其他方法可以轻松避免高 CC)?

这不是一件真正关键的事情。我只是不喜欢我的项目有我无法删除的警告;o)

编辑:代码示例

String process()
    String fieldName = this.getField() != null ? this.getField().getSchemaName() : null;
    String result = "";
    switch (op) {
    case PHRASE:
        result = "";
        if(!value.isEmpty() && value.get(0) != null) {
            result = value.get(0).toString();
        }
        break;
    case EQUALS:
    case GT:
    case GTE:
    case LT:
    case LTE:
    case NOT_EQUALS:
        result = prepareSingleParameterStatement(fieldName);
        break;
    case BETWEEN_EXC:
    case BETWEEN_INC:
        result = prepareDoubleParameterStatement(fieldName);
        break;
    case IN:
    case NOT_IN:
    case ALL_IN:
        result = prepareCollectionStatement(fieldName);
        break;
    case AND:
    case OR:
        result = prepareLogicalStatement();
        break;
    case NOT:
        result = prepareNotStatement();
        break;
    default:
        break;
    }
    return result;
}
4

3 回答 3

7

您可以使用枚举来构建状态机,而不是使用大型 switch 语句。您所做的是获取代码来解析每个 case 块中的文本,并将其放入每个枚举状态的方法中。

从例子

enum States implements State {
    XML {
        public boolean process(Context context) {
            if (context.buffer().remaining() < 16) return false;
            // read header
            if(headerComplete)
                context.state(States.ROOT);
            return true;
        }
    }, ROOT {
        public boolean process(Context context) {
            if (context.buffer().remaining() < 8) return false;
            // read root tag
            if(rootComplete)
                context.state(States.IN_ROOT);
            return true;
        }
    }
}

public void process(Context context) {
    socket.read(context.buffer());
    while(context.state().process(context));
}

使用枚举作为状态机

于 2014-05-23T08:21:20.753 回答
3

我建议用哈希图/字典和命令对象替换一个大开关:

Map<Op, Command> ops = new EnumMap<op>{{
  //initialize with different command objects implementing same interface
}};
command = ops.get(result);
result = command.prepare();
于 2014-05-23T08:21:12.383 回答
1

您可以将逻辑移动到具有共享接口的命令类(例如 MyCommandInterface),并在枚举值和枚举中的命令之间进行映射。

MyCommand 实现了 MyCommandInterface(已编辑)

public enum MyEnum {

  MyVALUE(new MyCommand()), MyVALUE2(new MyCommand());

  private MyCommandInterface command;

  public MyCommandInterface getCommand() {
     return command;
  }

  private MyEnum(MyCommandInterface command) {
    this.command = command;
  }
}
于 2014-05-23T09:00:08.113 回答