Cómo mejorar Ciclomático de Complejidad?

Ciclomático de Complejidad será alto para los métodos con un alto número de toma de declaraciones incluyendo, si es que/mientras que/para las declaraciones. Entonces, ¿cómo podemos mejorar?

Yo soy el manejo de un gran proyecto en el que estoy supuesto a la reducción de la CC para los métodos que se han CC > 10. Y hay muchos métodos con este problema. A continuación voy a enumerar algunos por ejemplo de patrones de código (no el código real) con los problemas que he encontrado. Es posible que ellos se puede simplificar?

Ejemplo de lo que en muchos casos la toma de declaraciones:

Caso 1)

if(objectA != null) //objectA is a pass in as a parameter
{
 objectB = doThisMethod();
 if(objectB != null)
 {
  objectC = doThatMethod();
  if(objectC != null)
  {
   doXXX();
  }
  else{
   doYYY();
  }
 }
 else
 {
  doZZZ();
 }
}

Caso 2)

if(a < min)
 min = a;

if(a < max)
 max = a;

if(b > 0)
 doXXX();

if(c > 0)
{
 doYYY();
}
else
{
 doZZZ();
 if(c > d)
  isTrue = false;

 for(int i=0; i<d; i++)
  s[i] = i*d;

 if(isTrue)
 {
  if(e > 1)
  {
   doALotOfStuff();
  }
 }
}

Caso 3)

//note that these String Constants are used elsewhere as diff combination,
//so you can't combine them as one
if(e.PropertyName.Equals(StringConstants.AAA) ||
e.PropertyName.Equals(StringConstants.BBB) ||
e.PropertyName.Equals(StringConstants.CCC) ||
e.PropertyName.Equals(StringConstants.DDD) ||
e.PropertyName.Equals(StringConstants.EEE) ||
e.PropertyName.Equals(StringConstants.FFF) ||
e.PropertyName.Equals(StringConstants.GGG) ||
e.PropertyName.Equals(StringConstants.HHH) ||
e.PropertyName.Equals(StringConstants.III) ||
e.PropertyName.Equals(StringConstants.JJJ) ||
e.PropertyName.Equals(StringConstants.KKK)) 
{
doStuff();
}

OriginalEl autor yeeen | 2010-12-17

4 respuestas

  1. 13

    Caso 1 – lidiar con esto simplemente por la refactorización en pequeñas funciones. E. g. el siguiente fragmento de código podría ser una función:

    objectC = doThatMethod();
    if(objectC != null)
    {
    doXXX();
    }
    else{
    doYYY();
    }

    Caso 2 – exactamente el mismo enfoque. Tomar el contenido de la cláusula else en una menor función auxiliar

    Caso 3 – hacer una lista de las cadenas de caracteres que desee comprobar y hacer una pequeña función auxiliar que compara una cadena en contra de muchas opciones (podría simplificarse aún más con linq)

    var stringConstants = new string[] { StringConstants.AAA, StringConstants.BBB etc };
    if(stringConstants.Any((s) => e.PropertyName.Equals(s))
    {
    ...
    }
    Para el caso 1 y caso 2… a veces hay muchas capas de ifs y todos de alguna manera relacionados entre sí, de modo muy difícil dividir. Para el caso 3… que es una buena idea, pero puedo tener muchos de estos cheques en el mismo método, si lo uso de esta manera significa que necesito muchas de estas matrices y el no de ifs no se reduce demasiado, por ejemplo, if(…){} else if(…){} else if(…){} else if(…){} …
    La reducción de ciclomático de la complejidad a menudo se traduce en más de código en general. Sin embargo todo el código nuevo que está haciendo un trabajo muy específicos y se pueden realizar pruebas unitarias fácilmente. En lugar de crear objetos dentro de su método de mirar en la inyección de dependencia/inyección de constructor y ver si se puede pasar a ellos. Mirar en las fábricas o el generador de patrones para la creación de objetos complejos, si es necesario, etc.. todo depende de tu caso concreto, pero si usted encuentra que las capas están estrechamente junto interrelacionados y, a continuación, su arquitectura no es bueno, ya que no debería ser el caso.

    OriginalEl autor Mark Heath

  2. 9

    Debe utilizar la refactorización Reemplazar Condicional con el Polimorfismo para reducir CC.

    La diferencia entre un condicional polimórficos código es que el polimórficos en el código de la decisión se hace en tiempo de ejecución. Esto le da más flexibilidad para agregar\cambiar o quitar condiciones sin modificar el código. Usted puede probar los comportamientos por separado por medio de la unidad de pruebas que mejora la capacidad de prueba. También, ya que habrá menos código condicional significa que el código es fácil de leer y CC es menos.

    Para mirar en comportamiento de patrones de diseño esp. Estrategia.

    Yo haría el primer caso como este para quitar el condicionales y, en consecuencia, los CC. Además, el código es más Orientado a Objetos, legible y probar así.

    void Main() {
    var objectA = GetObjectA();
    objectA.DoMyTask();
    }
    GetObjectA(){
    return If_All_Is_Well ? new ObjectA() : new EmptyObjectA();
    }
    class ObjectA() {
    DoMyTask() {
    var objectB = GetObjectB();
    var objectC = GetObjectC();
    objectC.DoAnotherTask();     //I am assuming that you would call the doXXX or doYYY methods on objectB or C because otherwise there is no need to create them
    }
    void GetObjectC() {
    return If_All_Is_Well_Again ? new ObjectC() : new EmptyObjectC();
    }
    }
    class EmptyObjectA() { //http://en.wikipedia.org/wiki/Null_Object_pattern
    DoMyTask() {
    doZZZZ();
    }
    }
    class ObjectC() {
    DoAnotherTask() {
    doXXX();
    }
    }
    class EmptyObjectB() { 
    DoAnotherTask() {
    doYYY();
    }
    }

    En el segundo caso es la misma que la primera.

    En el tercer caso –

    var myCriteria = GetCriteria();
    if(myCriteria.Contains(curretnCase))
    doStuff();
    IEnumerable<Names> GetCriteria() {
    //return new list of criteria.
    }
    No entiendo muy bien abt ur sugerencia para el caso 1… y lo que es “se Refieren a [Objeto Nulo Patrón][2]”?
    Bueno .. disculpas por el mal formato . El enlace está aquí – en.wikipedia.org/wiki/Null_Object_pattern. El Objeto Nulo patrón es acerca de encapsular el comportamiento de la manipulación de la capacidad de un objeto en una clase. Así que usted no tiene el código llena de Nulos Cheques. De esa manera usted puede evitar si las condiciones Null comprueba que es un caso de utilización de Polimorfismo para reemplazar la lógica condicional.
    También he elaborado la respuesta con algunos adicionales descripción en la parte superior. Por favor consulte.
    El número 4 en el “se Refieren a [Objeto Nulo Patrón][4]” se refiere a que en algún lugar del wiki? Lo siento, no cuajó.
    Y ¿por qué hay 2 EmptyObjectA clases, en caso de ser EmptyObjectB y EmptyObjectC lugar? Cos cuando objectA es nulo, no hace nada. Donde se GetObjectB()? Todavía estoy confundido.

    OriginalEl autor Unmesh Kondolikar

  3. 2

    Yo no soy un programador de C#, pero me voy a tomar una puñalada en ella.

    En el primer caso yo diría que los objetos no debe ser nulo en el primer lugar. Si esto es inevitable (normalmente es evitable), a continuación, me gustaría utilizar el pronto regreso a patrón:

    if ( objectA == NULL ) {
    return;
    }
    //rest of code here

    El segundo caso, obviamente no es realista código, pero me gustaría por lo menos en lugar de decir:

    if ( isTrue && e > 1 ) {
    DoStuff();
    }

    en lugar de utilizar dos por separado ifs.

    Y en el último caso, podría almacenar las cadenas para ser probado en una matriz/vector/mapa y el uso que los contenedores de los métodos para realizar la búsqueda.

    Y por último, aunque el uso de ciclomático de complejidad es “una buena cosa” ™ y yo mismo la utilizo, hay algunas funciones que naturalmente tienen que ser un poco complicado – validar la entrada del usuario es un ejemplo. A menudo me gustaría que el CC de la herramienta que yo uso (Monitor de Origen en http://www.campwoodsw.com libre y muy bueno) admite una lista blanca de las funciones que sé que debe ser algo complejo y que no quiero a la bandera.

    OriginalEl autor unquiet mind

  4. 1

    La última si en caso 2 puede ser simplificada:

     if(isTrue)
    {
    if(e > 1)
    {

    puede ser sustituido por

    if(isTrue && (e>1))

    caso 3 puede ser reescrita como:

    new string[]{StringConstants.AAA,...}
    .Contains(e.PropertyName)

    usted puede incluso hacer la matriz de cadena en un HashSet<String> para obtener O(1) el rendimiento.

    …aunque la versión simplificada de la declaración de si (para el caso 2) no reducirá el ciclomático de la complejidad del método.

    OriginalEl autor CodesInChaos

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *