¿Cuál es el significado de 'alta cohesión'?


28

Soy un estudiante que recientemente se unió a una empresa de desarrollo de software como pasante. De vuelta en la universidad, uno de mis profesores solía decir que debemos esforzarnos por lograr un "bajo acoplamiento y alta cohesión".

Entiendo el significado de bajo acoplamiento. Significa mantener el código de componentes separados por separado, para que un cambio en un lugar no rompa el código en otro.

Pero lo que se entiende por alta cohesión. Si significa integrar bien las diversas piezas del mismo componente entre sí, no entiendo cómo eso se vuelve ventajoso.

¿Qué se entiende por alta cohesión? ¿Se puede explicar un ejemplo para comprender sus beneficios?



1
¿El artículo de wikipedia no responde su pregunta lo suficiente? en.wikipedia.org/wiki/Cohesion_(computer_science)
Eoin Carroll

Hay un buen artículo sobre esto en: msdn.microsoft.com/en-us/magazine/cc947917.aspx
NoChance

1
@EoinCarroll: Desafortunadamente, el artículo de Wikipedia en este momento no da buenos ejemplos concretos con los que los nuevos programadores puedan trabajar. La teoría es buena y todo, pero realmente no se mantiene hasta que haya cometido los errores que rodean la baja cohesión. La alta cohesión es uno de esos temas que me ha llevado varios años de programación para comprender completamente por qué es importante y cómo lograrlo.
Spoike

Nunca entendí realmente Cohesión hasta que leí Clean Code. Tu también deberías.
Sebastian Redl

Respuestas:


25

Una forma de ver la cohesión en términos de OO es si los métodos de la clase están utilizando alguno de los atributos privados. Usando métricas como LCOM4 (Falta de métodos cohesivos), como lo señala el mosquito en esta respuesta aquí , puede identificar clases que podrían refactorizarse. La razón por la que desea refactorizar métodos o clases para que sean más coherentes es que hace que el diseño del código sea más simple para que otros lo usen . Créeme; la mayoría de los líderes tecnológicos y programadores de mantenimiento lo amarán cuando solucione estos problemas.

Puede usar herramientas en su proceso de compilación como Sonar para identificar baja cohesión en la base del código. Hay un par de casos muy comunes en los que puedo pensar que los métodos tienen poca "cohesión" :

Caso 1: El método no está relacionado con la clase en absoluto.

Considere el siguiente ejemplo:

public class Food {
   private int _foodValue = 10;

   public void Eat() {
     _foodValue -= 1;
   }

   public void Replenish() {
     _foodValue += 1;
   }

   public void Discharge() {
     Console.WriteLine("Nnngghhh!");
   }
}

Uno de los métodos, Discharge()carece de cohesión porque no toca a ninguno de los miembros privados de la clase. En este caso sólo hay un miembro privado: _foodValue. Si no hace nada con los elementos internos de la clase, ¿realmente pertenece allí? El método podría moverse a otra clase que podría llamarse, por ejemplo FoodDischarger.

// Non-cohesive function extracted to another class, which can
// be potentially reused in other contexts
public FoodDischarger {
  public void Discharge() {
    Console.WriteLine("Nnngghhh!");
  }
}

Lo estás haciendo en Javascript, ya que las funciones son objetos de primera clase, la descarga puede ser una función libre:

function Food() {
    this._foodValue = 10;
}
Food.prototype.eat = function() {
    this._foodValue -= 1;
};
Food.prototype.replenish = function() {
    this._foodValue += 1;
};

// This
Food.prototype.discharge = function() {
    console.log('Nnngghhh!');
};
// can easily be refactored to:
var discharge = function() {
    console.log('Nnngghhh!');
};
// making it easily reusable without creating a class

Caso 2: Clase de utilidad

Este es realmente un caso común que rompe la cohesión. Todo el mundo ama las clases de utilidad, pero esto generalmente indica fallas de diseño y la mayoría de las veces hace que la base de código sea más difícil de mantener (debido a la alta dependencia asociada con las clases de utilidad). Considere las siguientes clases:

public class Food {
    public int FoodValue { get; set; }
}

public static class FoodHelper {

    public static void EatFood(Food food) {
        food.FoodValue -= 1;
    }

    public static void ReplenishFood(Food food) {
        food.FoodValue += 1;
    }

}

Aquí podemos ver que la clase de utilidad necesita acceder a una propiedad en la clase Food. Los métodos en la clase de utilidad no tienen cohesión en absoluto en este caso porque necesita recursos externos para hacer su trabajo. En este caso, ¿no sería mejor tener los métodos en la clase con la que están trabajando (como en el primer caso)?

Caso 2b: objetos ocultos en clases de utilidad

Hay otro caso de clases de utilidad donde hay objetos de dominio no realizados. La primera reacción instintiva que tiene un programador al programar la manipulación de cadenas es escribir una clase de utilidad para ella. Como el que aquí valida un par de representaciones de cadenas comunes:

public static class StringUtils {

  public static bool ValidateZipCode(string zipcode) {
    // validation logic
  }

  public static bool ValidatePhoneNumber(string phoneNumber) {
    // validation logic
  }

}

Lo que la mayoría no se da cuenta aquí es que un código postal, un número de teléfono o cualquier otra repetición de cadena puede ser un objeto en sí mismo:

public class ZipCode {
    private string _zipCode;
    public bool Validates() {
      // validation logic for _zipCode
    }
}

public class PhoneNumber {
    private string _phoneNumber;
    public bool Validates() {
      // validation logic for _phoneNumber
    }
}

La noción de que no debe "manejar cadenas" directamente se detalla en esta publicación de blog de @codemonkeyism , pero está estrechamente relacionada con la cohesión porque la forma en que los programadores usan cadenas al poner la lógica en las clases de utilidad.


Ahora, si tan solo pudiéramos obtener nuestros ORM para manejar adecuadamente nuestras clases ZipCode y PhoneNumber personalizadas: |
Pete

+1 buenos ejemplos. Para el último punto, vea también sourcemaking.com/refactoring/primitive-obsession
AlexFoxGill

@Pete Su ORM lo manejará si proporciona operadores de conversión de cadena a su tipo definido (Código postal, Número de teléfono): msdn.microsoft.com/en-us/library/85w54y0a.aspx
Marcus

9

Alta cohesión significa mantener juntas cosas similares y relacionadas, unir o fusionar partes que comparten contenido, funcionalidad, razón u objetivo . En otras palabras, una baja cohesión podría significar, por ejemplo, una entidad de función / clase / código que sirve para múltiples propósitos en lugar de estar " al punto ". Una de las ideas principales es hacer una cosa y hacerlo bien . Otros podrían incluir el hecho obvio de que no se replica una funcionalidad similar en muchos lugares. Esto también mejora la localidad de la base del código, se encuentran ciertos tipos de cosas en un lugar determinado (archivo, clase, conjunto de funciones, ...) en lugar de estar dispersos.

Como ejemplo, considere una clase que tiene dos o tres propósitos: Carga / almacena recursos (por ejemplo, un archivo) y luego analiza y muestra el contenido. Dicha clase tiene baja cohesión porque gestiona al menos dos tareas separadas que no están relacionadas en absoluto (E / S de archivo, análisis y visualización). Un diseño de alta cohesión podría usar clases distintas para cargar y almacenar el recurso, analizarlo y luego mostrarlo.

Por otro lado, el bajo acoplamiento tiene como objetivo mantener distintas cosas separadas, de modo que interactúen entre sí lo menos posible, lo que reduce la complejidad y simplifica el diseño.


7

Significa que las partes de un objeto dado están estrechamente relacionadas con la función del objeto. Esto significa que hay muy poco o ningún desperdicio dentro del objeto en términos de función o responsabilidad. Esto a su vez puede mejorar la comprensión de para qué se supone que debe usarse el objeto en cuestión.


¿No se aplica también a un nivel superior al de los objetos? por ejemplo, agrupar objetos / funciones relacionadas con una tarea en espacios de nombres?
stijn
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.