uml-basico-patrones

UML básico para entender diagramas de patrones

  • 5 min

Un diagrama de clases UML es una representación visual de las clases de un sistema y de las relaciones entre ellas. Si abres cualquier libro sobre patrones de diseño (incluido el famoso GoF), vas a encontrarte con un montón de «cajitas y flechas» de este tipo.

Esas cajas son diagramas UML (Unified Modeling Language).

Para seguir este curso no necesitas dominar UML ni saber crear diagramas complejos de despliegue o secuencia. Sí necesitas saber leer un diagrama de clases.

Los patrones son, en esencia, estructuras de clases y sus relaciones. Si no entendemos qué significa que una flecha tenga la punta de diamante o sea punteada, no entenderemos la diferencia entre una asociación y una composición, y por tanto, implementaremos mal el patrón.

Vamos a ver el kit de supervivencia de UML para seguir el curso.

La clase

La unidad básica en estos diagramas es la Clase. Se representa como un rectángulo dividido (normalmente) en tres secciones:

  • Nombre de la clase: por ejemplo, Customer u OrderFactory. Si aparece en cursiva, representa una clase abstracta.
  • Atributos: las variables o datos (estado).
  • Métodos: las funciones (comportamiento).

Además, verás unos símbolos delante de los atributos y métodos que indican su visibilidad:

  • + Public: Accesible desde cualquier lugar.
  • - Private: Solo accesible desde la propia clase.
  • # Protected: Accesible desde la clase y sus derivadas (herencia).

En los diagramas de patrones, a menudo se omiten los atributos para simplificar y centrarse solo en los métodos clave que definen el patrón.

Las relaciones

Aquí es donde está la “chicha”. Las líneas que conectan las clases nos dicen cómo interactúan entre sí. Vamos a ver las 5 más importantes para entender patrones.

Herencia

Representa la relación “Es un” (Is-a). Se dibuja con una línea continua terminada en un triángulo hueco que apunta a la clase padre (superclase).

  • Significado: La clase hija hereda atributos y métodos del padre.
  • Código C#: public class Perro : Animal { ... }

Implementación

Representa la relación de “Cumple el contrato”. Se usa con Interfaces. Se dibuja con una línea discontinua terminada en un triángulo hueco apuntando a la interfaz.

  • Significado: La clase concreta implementa los métodos definidos en la interfaz. Esto es clave en patrones como Strategy o Observer.
  • Código C#: public class LogFile : ILogger { ... }

Asociación

Es la relación más genérica. Representa “Tiene un” o “Conoce a”. Se dibuja con una línea continua simple (a veces con una flecha abierta al final para indicar navegabilidad).

  • Significado: Una clase contiene una referencia a otra clase como atributo.
  • Ejemplo: Un objeto Usuario tiene una propiedad de tipo Direccion.

Agregación y composición

Aquí es donde mucha gente se lía. Ambas son tipos de Asociación, pero con matices importantes sobre el ciclo de vida de los objetos.

Agregación (el diamante blanco ◇)

Representa una relación “débil”. El objeto “todo” tiene objetos “parte”, pero las partes pueden vivir independientemente.

  • Símbolo: Línea continua con un diamante hueco (blanco) en el extremo del contenedor.
  • Ejemplo: Un Equipo de fútbol y sus Jugadores. Si el equipo desaparece, los jugadores siguen existiendo (pueden irse a otro equipo).
  • En C++: Normalmente un puntero (Player*) o referencia que no borramos en el destructor.

Composición (el diamante negro ◆)

Representa una relación “fuerte”. El objeto “todo” es dueño absoluto de las “partes”. Si el contenedor muere, las partes mueren con él.

  • Símbolo: Línea continua con un diamante relleno (negro) en el extremo del contenedor.
  • Ejemplo: Una Casa y sus Habitaciones. Si destruyes la casa, las habitaciones dejan de existir. No tiene sentido una habitación “suelta” sin casa.
  • En C++: Un objeto por valor, o un std::unique_ptr que se borra en el destructor.

Dependencia

Representa una relación temporal o de uso. “Usa a”. Se dibuja con una línea discontinua con una flecha abierta.

  • Significado: Una clase usa a otra, pero no la contiene como atributo. Suele ocurrir cuando una clase recibe a otra como parámetro en un método.
  • Ejemplo: Un método Imprimir(Documento doc) en la clase Impresora. La impresora “usa” al documento para imprimirlo, pero no “tiene” un documento permanentemente.
  • Importancia: Si la clase Documento cambia, la clase Impresora podría verse afectada.

Resumen visual para desarrolladores

Para que quede cristalino, vamos a traducirlo a pseudo-código, que es como mejor nos entendemos nosotros:

RelaciónUML (flecha)ConceptoCódigo mental
Herencia───▷ (Continua)“Es un”class B : A { }
Implementación- - ▷ (Discontinua)“Cumple contrato”class B : InterfaceA { }
Composición◆─── (Negro)“Yo te creo y te destruyo”new Parte() dentro del Constructor
Agregación◇─── (Blanco)“Te tengo, pero eres libre”Recibe Parte desde fuera y la guarda
Dependencia- - -> (Flecha)“Te uso un momento”Recibe Obj en parámetro de método