Как я могу уменьшить Cyclomatic Complexity этого?
У меня есть метод, который получает объект и делает что-то, основанное на том, какой тип объекта он обнаруживает:
void receive(Object object) {
if (object instanceof ObjectTypeA) {
doSomethingA();
}
else {
if (object instanceof ObjectTypeB) {
doSomethingB();
}
else {
if (object instanceof ObjectTypeC) {
doSomethingC();
}
else {
if (object instanceof ObjectTypeD) {
doSomethingD();
}
else {
// etc...
}
}
}
}
}
Как я могу уменьшить Cyclomatic Complexity? Я искал вокруг, но не мог найти ничего полезного.
Ответы
Ответ 1
Нельзя ли использовать объектно-ориентированный подход для этого? Создайте интерфейс, который имеет метод doSomething()
, затем создайте подклассы, которые реализуют желаемое поведение? Тогда вызов object.doSomething()
выполнил бы соответствующее поведение?
Ответ 2
Цикломатическая сложность - это мера, основанная на структуре графа кода. В частности, он основан на количестве возможных путей через код; см. здесь для более подробной информации. Хотя существует корреляция между CC и тем, что типичный программист будет рассматривать как сложность кода, это не одно и то же. Например:
-
CC не учитывает семантику кода; например какой именно такой-то метод называется, или математические свойства алгоритма.
-
CC не учитывает шаблоны проектирования и кодирования. Итак, что-то, что говорит CC, сложно, может быть простым для тех, кто понимает используемый шаблон.
Можно сказать, что взаимосвязь между CC и реальной сложностью кода похожа на отношения между IQ и реальным интеллектом.
Таким образом, Cyclomatic Complexity следует рассматривать как показатель того, где сложные части вашего кода... не как истинная мера сложности или качества кода. Действительно, очень сложный код не обязательно низкого качества. Часто сложность присуща, и попытка избавиться от нее только усугубляет ситуацию.
В этом конкретном примере высокая CC-мерка не соответствует чему-то, что может вызвать у типичного программиста какие-либо трудности. Лучший ответ (ИМО) заключается в том, чтобы оставить этот метод в покое. Мел это как ложный позитив.
Ответ 3
void receive(ObjectTypeA object) {
doSomethingA();
}
void receive(ObjectTypeB object) {
doSomethingB();
}
void receive(ObjectTypeC object) {
doSomethingC();
}
...
// Your final 'else' method
void receive(Object object) {
doSomethingZ();
}
Ответ 4
Почему необходимо уменьшить сложность? Это достаточно простой образец, который любой компетентный разработчик видел бы в качестве тривиальной функции.
Я бы, вероятно, написал это так
if (object instanceof ObjectTypeA)
{
doSomethingA();
}
else if (object instanceof ObjectTypeB)
{
doSomethingB();
}
else if (object instanceof ObjectTypeC)
{
doSomethingC();
}
Если для удовлетворения некоторой эзотерической необходимости "CC должен быть меньше x", то общее правило, согласно которому стандарты должны содержать поддерживаемый код, будет означать, что это приемлемо независимо от того, насколько высокий CC получает.
Ответ 5
Никогда не было цели "уменьшить цикломатическую сложность", хотя бывали времена, когда мне платили LOC.
Вы кодируете "достаточно хорошо". Мои глаза спотыкаются о скобках, поэтому я пожертвовал бы некоторой производительностью и сделал следующее (предоставление типов A, B и т.д. Не в одной иерархии):
receive(Object object) {
if (object intanceof ObjectTypeA) doSomethingA();
if (object instanceof ObjectTypeB) doSomethingB();
...
или (если они находятся в одной иерархии):
receive(Object object) {
if (object intanceof ObjectTypeA) { doSomethingA(); return; }
if (object instanceof ObjectTypeB) { doSomethingB(); return; }
...
Не знаю, снизит ли он цикломатическую штуковину и не волнует.