Modelos de Dominio en Programación Orientada a Objetos

Clase 14 de 24Curso de Arquitecturas Limpias para Desarrollo de Software

Contenido del curso

Resumen

Cuando trabajamos con transaction scripts, los objetos suelen estar partidos a la mitad: unos tienen datos sin comportamiento y otros tienen comportamiento sin datos. Esa separación artificial se conoce como modelos anémicos y desaprovecha el verdadero potencial de la programación orientada a objetos. El modelo de dominio resuelve exactamente ese problema al reunir datos y comportamiento en un mismo objeto, creando representaciones mucho más expresivas y reutilizables.

¿Qué diferencia un modelo de dominio de un modelo de base de datos?

Una confusión muy frecuente es pensar que cualquier clase con propiedades ya es una entidad de dominio. En realidad, una clase configurada con anotaciones de persistencia —llaves primarias, llaves foráneas, validaciones de longitud de campos— es simplemente un modelo de base de datos [0:56]. Esa clase vive en la capa de infraestructura y está atada a un framework específico como Entity Framework.

El modelo de dominio, en cambio, se enfoca en representar las reglas de negocio. No le importa cómo se almacenan los datos, sino qué operaciones tienen sentido sobre ellos. Esta distinción es fundamental para mantener una arquitectura limpia donde el dominio permanezca independiente de los detalles técnicos.

¿Qué elementos componen un modelo de dominio?

Un modelo de dominio puede incluir varios tipos de componentes que se complementan entre sí [1:40]:

  • Entidades: el insumo principal, objetos con identidad propia.
  • Objetos de valor: objetos sin identidad que agrupan datos y operaciones relacionadas.
  • Herencia: clases que extienden a otras para añadir comportamiento especializado.
  • Relaciones: conexiones entre entidades y otros objetos del dominio.
  • Patrones de diseño: estructuras que aprovechan herencia y relaciones para resolver problemas complejos.

¿Cómo luce una entidad con comportamiento real?

En el ejemplo práctico, la entidad Flight (vuelo) deja de ser un contenedor pasivo de datos y se convierte en un objeto con capacidad de acción [2:16]. Incorpora un método AddBooking que agrega reservaciones y ajusta dinámicamente el número de asientos disponibles según los pasajeros de cada reserva. También incluye IsAvailable, que verifica si realmente hay sillas suficientes para un grupo de pasajeros.

Este enfoque tiene una ventaja clara: la lógica que pertenece al vuelo vive dentro del vuelo. No queda dispersa en un servicio externo ni en un método enorme con instrucciones secuenciales.

¿Qué es un objeto de valor y para qué sirve?

El ejemplo más clásico de un objeto de valor (value object) son los strings: contienen un grupo de caracteres y sobre ellos se ejecutan operaciones [3:12]. En el caso del dominio de vuelos, se crea un objeto de valor llamado Route que agrupa dos atributos —origen y destino— que normalmente estarían sueltos por toda la aplicación.

Route además incluye un método para validar si la ruta es correcta [3:34]. Por ejemplo, detecta si alguien creó una ruta sin origen, sin destino, o con el mismo valor en ambos campos. A diferencia de una entidad, el objeto de valor no tiene identidad propia: dos rutas con el mismo origen y destino son equivalentes. Su utilidad radica en agrupar datos relacionados y encapsular validaciones que les corresponden.

¿Cómo cambia el servicio al usar modelos de dominio?

El servicio se transforma significativamente [4:06]. En lugar de contener toda la lógica de negocio, empieza a delegar responsabilidades a las entidades. Cuando necesita saber si una ruta es válida, le pregunta al objeto Route. Cuando necesita verificar disponibilidad, le pide al vuelo que lo resuelva con IsAvailable. Cuando registra una reserva, utiliza AddBooking directamente sobre la entidad.

El resultado es un servicio más liviano y unas entidades más poderosas. Se le quita carga al servicio y se distribuye el comportamiento donde realmente pertenece. Esto produce una programación orientada a objetos más cohesionada y con mayor capacidad de reutilización [4:42].

Si has trabajado con modelos anémicos y quieres migrar hacia un enfoque más rico, el primer paso es identificar qué lógica del servicio realmente pertenece a tus entidades y moverla allí. Comparte tu experiencia aplicando esta transición en tus proyectos.