Действительно ли использование карты действительно снижает цикломатическую сложность?
Предположим, что у меня есть оригинальный метод ниже.
public String someMethod(String str) {
String returnStr;
if("BLAH".equals(str)) {
returnStr="ok";
} else if ("BLING".equals(str)) {
returnStr="not ok";
} else if ("BONG".equals(str)) {
returnStr="ok";
}
return returnStr;
}
Преобразовывает ли снизу действительно уменьшает CC?
Map<String, String> validator = new HashMap<String,String>();
validator.put("BLAH","ok");
validator.put("BLING","not ok");
validator.put("BONG","ok");
public String someMethod(String str) {
return validator.get(str);
}
Ответы
Ответ 1
Да, в вашем случае. Говоря простыми словами, циклическая сложность представляет собой ряд линейно-независимых способов достижения конца фрагмента кода от начальной точки. Таким образом, любой условный оператор увеличивает CC вашего кода.
(если вопрос OP каким-то образом связан с тегом testing
). Однако уменьшение CC не уменьшает количество unit test, которое должно быть записано для покрытия вашего кода: CC дает вам только нижнюю границу счетчика тестов. Для хороших тестов модуляции покрытия должны охватывать все конкретные случаи, а во втором случае вы не уменьшаете это количество конкретных случаев, вы только делаете свой код более удобочитаемым.
Ответ 2
Да, поскольку циклическая сложность определяет число линейных независимых путей в графе потока управления плюс один. В вашем втором примере есть только один путь, первый имеет несколько путей через ветки if
. Однако, похоже, что цикломатическая сложность действительно является проблемой здесь. Вы можете подставить свой метод таким образом, чтобы сделать его более читаемым:
public String someMethod(String str) {
switch(str) {
case "BLAH":
case "BONG": return "ok";
case "BLING": return "not ok";
default: return null;
}
}
Ответ 3
Короткий ответ: да, использование Hashmap в вашем случае уменьшает Cyclomatic complexcity.
Подробный ответ: Цикломатическая сложность по википедии
Это количественная мера количества линейно независимых путей через программный исходный код.
Существуют различные способы решения дел if-else. Операторы if-else делают код менее читаемым, его трудно понять. Эти if-else также плохи, поскольку каждый раз, когда вы добавляете/удаляете/изменяете в случаях, вам необходимо изменить существующие файлы кода, где ваша другая бизнес-логика остается такой же, и из-за изменения этих файлов вам необходимо протестировать их все снова. Это приводит к проблемам с обслуживанием, а также во всех местах, где нам необходимо следить за случаями. Аналогичные проблемы существуют и с операторами switch, хотя они мало читаемы.
То, как вы использовали, также уменьшает различные логические пути выполнения. Другой альтернативный подход выглядит следующим образом.
Вы можете создать интерфейс, скажем IPair
. Пусть этот интерфейс определяет абстрактный метод public String getValue();
Позволяет определить разные классы для каждого имеющегося у нас случая и BlahMatch.java, Bling.java and Bong.java
реализовать IPair
, а в реализации метода getValue()
вернуть соответствующий String
.
public String someMethod(IPair pair) {
return pair.getValue();
}
Преимущество вышеуказанного подхода заключается в том, что если у вас есть несколько новых папок, вы все равно сможете создать новый класс и легко передать объект своего нового класса, просто вам нужно, чтобы ваш класс обеспечивал реализацию для IPair
.