cohesion-y-acoplamiento

Qué son las métricas cohesión y acoplamiento entre clases

  • 4 min

La cohesión y el acoplamiento son dos formas de medir cómo de bien organizado está un diseño de software.

Cuando empezamos a programar, nuestra principal preocupación es simplemente “que funcione”. Con el tiempo, nos damos cuenta de que escribir código que funcione es solo la mitad de la batalla. La otra mitad es hacer código que sea mantenible, escalable y robusto.

Estos dos términos suelen ir de la mano y se repiten como un mantra en diseño de software: alta cohesión y bajo acoplamiento.

Estos conceptos no son exclusivos de la Programación Orientada a Objetos, pero es en la POO donde cobran una relevancia crítica para diseñar clases y sistemas eficientes.

¿Qué significan realmente? ¿Por qué son tan importantes? Y, sobre todo, ¿cómo los aplicamos en nuestro día a día? Vamos a verlo en profundidad 👇.

¿Qué es la Cohesión?

La Cohesión es la medida de cuán relacionadas y enfocadas están las responsabilidades de un módulo, clase o función.

En términos sencillos: ¿Cuánto sentido tiene que estas cosas estén juntas?

  • Una clase con Alta Cohesión es aquella que se dedica a una única tarea o a un conjunto de tareas estrechamente relacionadas.
  • Por el contrario, una clase con Baja Cohesión (o “cohesión débil”) intenta hacer demasiadas cosas dispares, convirtiéndose en lo que llamamos un “God Object” u “Objeto Dios”.

Supongamos una clase GestorDePedidos. Si esta clase:

  1. Valida los datos del pedido.
  2. Conecta con la base de datos para guardar el pedido.
  3. Genera un PDF con la factura.
  4. Envía un email al cliente.

Tenemos un problema de baja cohesión. Esta clase hace de todo. Si cambia la forma de enviar emails, tenemos que tocar la clase de pedidos. Si cambia la base de datos, tocamos la clase de pedidos.

Para lograr una alta cohesión, deberíamos separar estas responsabilidades. GestorDePedidos solo debería orquestar el proceso, delegando en:

  • ValidadorDePedidos (Lógica de negocio)
  • RepositorioDePedidos (Persistencia)
  • GeneradorDeFacturas (Documentos)
  • ServicioDeNotificacion (Emails)

¿Qué es el acoplamiento?

El Acoplamiento es la medida de cuán dependientes son los módulos entre sí. Es el grado en que un cambio en una clase obliga a realizar cambios en otra.

Aunque hay muchos niveles, podemos simplificarlo en:

  1. Acoplamiento Fuerte (Tight Coupling): Ocurre cuando una clase depende de detalles concretos de otra. Por ejemplo, instanciar directamente una clase con new dentro de otra.
  2. Acoplamiento Débil (Loose Coupling): Ocurre cuando una clase depende de abstracciones (interfaces o clases abstractas) y no de implementaciones concretas.

El objetivo: Alta cohesión y bajo acoplamiento

El objetivo de un buen diseño es maximizar la cohesión y minimizar el acoplamiento.

MétricaObjetivo¿Por qué?
CohesiónAltaFacilita entender qué hace la clase. Reduce la complejidad.
AcoplamientoBajoFacilita los cambios. Si modifico A, no rompo B. Facilita el testeo.

Veamos un ejemplo práctico en código para ilustrar la diferencia.

Aquí tenemos una clase con baja cohesión (hace muchas cosas) y alto acoplamiento (depende de la consola y de una forma específica de guardar).

// Mal diseño: Baja cohesión y Alto acoplamiento
public class ProcesadorDePedidos
{
    public void Procesar(Pedido pedido)
    {
        // 1. Lógica de validación mezclada
        if (pedido.Importe <= 0)
        {
            Console.WriteLine("Error: Importe no válido"); // Acoplado a la consola
            return;
        }

        // 2. Lógica de base de datos mezclada (Hardcoded)
        // Supongamos aquí código SQL directo...
        Console.WriteLine("Guardando en SQL Server...");

        // 3. Lógica de notificación mezclada
        Console.WriteLine("Enviando email al usuario...");
    }
}

Copied!

Si queremos cambiar la base de datos a un archivo de texto, o enviar un SMS en vez de un email, tenemos que modificar y recompilar esta clase, arriesgándonos a romper la validación.

Vamos a aplicar alta cohesión separando responsabilidades y bajo acoplamiento usando interfaces.

// Definimos contratos (Interfaces) para bajar el acoplamiento
public interface IRepositorioPedidos { void Guardar(Pedido p); }
public interface INotificador { void Enviar(string mensaje); }

// Clase coordinadora con Alta Cohesión
public class ProcesadorDePedidos
{
    private IRepositorioPedidos _repo;
    private INotificador _notificador;

    // Inyección de dependencias (Bajo Acoplamiento)
    // No hacemos 'new', nos lo pasan.
    public ProcesadorDePedidos(IRepositorioPedidos repo, INotificador notif)
    {
        _repo = repo;
        _notificador = notif;
    }

    public void Procesar(Pedido pedido)
    {
        if (pedido.Importe <= 0)
            throw new Exception("Pedido inválido"); // Validación básica

        _repo.Guardar(pedido);       // Delegamos persistencia
        _notificador.Enviar("Ok");   // Delegamos notificación
    }
}

Copied!
  • Ahora ProcesadorDePedidos tiene alta cohesión: su única responsabilidad es coordinar el proceso.
  • Y tiene bajo acoplamiento: no sabe si guardamos en SQL o en un archivo, ni si notificamos por email o por WhatsApp. Solo sabe que hay algo que cumple la interfaz.