Tipos de cohesión

En la última entrega, hemos visto que son tanto la cohesión como el acoplamiento. Además hemos repasado los beneficios que nos aportan cada uno de ello y como afectan a la calidad del código que generamos. En este artículo seguimos profundizando en uno de estos conceptos, abordando los distintos tipos de cohesión existentes, e incluyendo ejemplos para tener una visión mucho más clara y práctica.

Cohesión

Al igual que hicimos en la entrada Cohesión y acoplamiento, en la que puedes encontrar una buena descripción sobre estos dos conceptos, trataremos la cohesión única y exclusivamente a nivel de clase.

Y para no enrollarnos más, veamos el índice de contenidos y vayamos al lío.

Idoneidad de los tipos de cohesión

La cohesión dentro de una clase puede conseguirse utilizando diversas técnicas. Atendiendo a estas técnicas existen siete tipos de cohesión, algunas de las cuales son mucho más recomendables que otras. Así, si las ordenamos de más recomendable a menos recomendable tendremos lo siguiente:

  • Cohesión funcional.
  • Cohesión secuencial.
  • Cohesión comunicacional.
  • Cohesión procedimental.
  • Cohesión lógica.
  • Cohesión temporal.
  • Cohesión casual.

Es más, si vamos un paso más allá y dividimos los tipos de cohesión en función de su idoneidad, podemos decir que existen tres grupos:

  • Tipo de cohesión óptimo: funcional.
  • Tipos de cohesión recomendados: secuencial, comunicacional y procedimental.
  • Tipos de cohesión no recomendados: lógica, temporal y casual.

Tipos de cohesión

Veamos ahora los tipos de cohesión uno a uno.

Cohesión funcional

Es el tipo de cohesión óptimo, todos los elementos están relacionados para realizar una única tarea, lo que propicia el cumplimiento del principio de responsabilidad única (SRP). También favorecerá clases de fácil comprensión y mantenimiento.

Veamos un ejemplo:

public class updateStatusBar {
    

   private String message;
   private int level;

   public updateStatusBar(String message, int level) {

      this.setMessage(message);
      this.setLevel(level);

      this.clear();
      this.update();

   }

   private void clear() {

      this.message = "";
      this.level = 0;
      this.update();

   }

   private void setMessage(String message) {

      this.message = message;

   }

   private void setLevel(int level) {

      this.level = level;

   }

   private void update() {

      ...

   }    
    
}

Cohesión secuencial

Los métodos involucrados deben seguir un estricto orden de ejecución para completar la tarea. La cohesión se consigue tanto mediante la propia ejecución secuenciales de los métodos como mediante la utilización del mismo conjunto de datos, utilizando la salida de algunos métodos (return) como entrada por parámetros de otros.

Con el siguiente ejemplo lo veremos mucho más claro. Fijaos que ninguna de las instrucciones puede ser ejecutada sin antes haber hecho lo propio con la anterior, y cómo los resultados de la ejecución de los métodos pasan a los siguientes en forma de parámetros.

public class salesReport {

   private ReportType type;    

   public printOverviewReport () {

      Params params = this.getParams();
      String sql = this.generateSql(params);
      Result results = this.gelResults(sql);
      this.printReport(params, results);
      
   }

   ...
   
}

Cohesión comunicacional

Este tipo de cohesión se produce cuando los elementos se relacionan mediante el uso del mismo conjunto de datos, o dicho de otra forma, agrupamos en una misma unidad de software los componentes que hacen uso de un mismo conjunto de datos. Esto ocurre independientemente de que no estén relacionados funcionalmente.

Es un tipo de cohesión más habitual en un nivel superior de abstracción, por ejemplo, incluyendo en un mismo paquete distintos componentes, aunque puede darse perfectamente a nivel de clase.

En el siguiente ejemplo vemos como una misma clase realiza tareas funcionalmente diferentes: operaciones aritméticas y operaciones trigonométricas. La cohesión se obtiene mediante la utilización del mismo conjunto de datos.

public class numberOperations {
    
   private float numberA;
   private float numberB;

   public void setNumberA(float number) {

      this.numberA = number;

   }

   public void setNumberB(float number) {

      this.numberB = number;

   }

   public float sum () {

      return numberA + numberB;
      
   }

   public float subtract () {

      return numberA - numberB;
      
   }

   public double triangleHypotenuse() {

      return Math.sqrt(Math.pow(numberA, 2) + Math.pow(numberB, 2));

   }

   public float rectangleArea() {

      return this.numberA * this.numberB;

   }
    
}

Cohesión procedimental

Es bastante similar a la cohesión secuencial en cuanto que es necesario el seguimiento de un riguroso orden de ejecución, pero a diferencia de ésta, no existe una comunicación mediante parámetros.

public class salesReport {
    
   public assambly () {

      this.attachHeader();
      this.attachBody();
      this.attachFooter();
      
   }

   ...
   
}

Cohesión lógica

La relación entre los elementos es lógica en lugar de funcional. Por norma habitual los elementos pertenecen a la misma clase, las operaciones están relacionadas, pero las acciones que realizan varían significativamente en función de algún factor.

public class displayItemProperties {
    
   item Item;

   public displayItemProperties (item Item) {

      this.Item = Item;
      this.display();
      
   }
   
   private void display() {

      switch (this.Item.getType()) {

         case "shoes" : {
            this.displayShoesProperties();
            break;
         }
         case "shirt" : {
            displayShirtProperties();
            break;
         }
         case "trousers" : {
            displayTrousersProperties();
            break;
         }

      }

   }

   ...
    
}

En este caso quizás sería más acertado crear una subclase por cada tipo de producto y sobrescribir el método display().

Cohesión temporal

Es un tipo de cohesión nada recomendable, los elementos están cohesionados en base a un hecho que sucede en un determinado espacio de tiempo. Es habitual encontrar este tipo de cohesión en métodos de inicialización o finalización.

Con el siguiente ejemplo lo veremos muy claro, hemos incluido en la misma clase métodos funcionalmente muy dispares cuya única relación es que se ejecutan tras habernos autentificado en el sistema.

public class postLogIn {

   private int userID;
    
   public postLogInActions () {

      this.logAuth();
      this.retrieveNewAlerts();
      this.retrieveHewMessages();
      this.retrieveStats();
      this.printDashboard();
     
   }

   ...
   
}

Cohesión casual

Es el peor tipo de cohesión. Los elementos no tienen ninguna relación conceptual ni de ningún otro tipo de los que hemos visto hasta ahora, tan solo están agrupados en la misma unidad de software. Al igual que en la cohesión lógica, el resultado será siempre una clase multifuncional con una cohesión muy baja en el mejor de los casos.

public class posUtilities {
    
   public static float priceRound (float price) { ... }

   public static void updateTopBarPrice (float price) { ... }
    
   public static void cleanLogFiles () { ... }
    
   public static void reindexDb() { ... }

}

Conclusión

Lograr la cohesión a nivel de clase es relativamente sencillo, pero conseguir una clase funcionalmente cohesionada es algo más complicado y requiere de un mayor esfuerzo en la fase de diseño del software.

No obstante, ese esfuerzo extra invertido para conseguirlo se verá recompensado rápidamente, contribuyendo a evitar comprometernos con una deuda tecnológica que nos obligue a pagar intereses en el futuro.

Créditos, referencias y artículos relacionados

Deja un comentario

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