繁体   English   中英

在大型枚举上使用开关盒时,是否可以避免高环路复杂性(警告)?

[英]Can high cyclomatic complexity (warnings) be avoided when using switch-case on a large enum?

假设一个方法根据相当大的枚举值选择一个动作。 我们的声纳现在抱怨这种方法具有很高的圈复杂度(当然是关于案例陈述的数量)。

我知道,大型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;
}

您可以使用枚举来构建状态机,而不是使用大型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));
}

使用枚举作为状态机

我建议用hashmap / dictionary和命令对象替换一个大的开关:

Map<Op, Command> ops = new EnumMap<op>{{
  //initialize with different command objects implementing same interface
}};
command = ops.get(result);
result = command.prepare();

您可以将逻辑移动到具有共享接口的命令类(在exammple中使用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;
  }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM