Modelos de Dominio en Programación Orientada a Objetos

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

Resumen

¿Qué es un modelo de dominio?

El modelo de dominio es una forma avanzada de organizar el dominio en programación orientada a objetos (POO). Contrario a los modelos anémicos, donde los objetos no aprovechan al máximo las capacidades de POO al tener datos o comportamientos limitados, un modelo de dominio integra tanto comportamientos como datos. Esto permite que los objetos no solo guarden información, sino que puedan realizar operaciones significativas y manejar sus propios métodos, lo cual enriquece enormemente la interacción y funcionalidad del sistema.

¿Cómo se diferencia un modelo de dominio de un modelo de base de datos?

A menudo, se crea confusión entre los modelos de dominio y los modelos de base de datos. Un modelo de base de datos, generalmente referido como esquema, está estructurado específicamente para la gestión de datos en un entorno de persistencia, como puede ser una base de datos SQL con herramientas como Entity Framework. Aquí es común encontrar clases que denotan características de los campos de la base de datos como llaves primarias, foráneas y validaciones de datos. En cambio, en un modelo de dominio, las clases no están necesariamente ligadas a la estructura de la base de datos sino que se centran en representar la lógica y comportamiento del negocio. Esto implica que se aprovechan los principios de POO como la herencia y el polimorfismo para crear objetos que interactúan de forma más rica dentro de la aplicación.

¿Qué componentes puede incluir un modelo de dominio?

Al desarrollar un modelo de dominio, se consideran varios elementos que potencian su funcionalidad y mantenibilidad. Estos incluyen:

  • Entidades: Son los elementos centrales que representan objetos del mundo real y tienen una identidad única en el contexto del dominio.

  • Objetos de valor: A diferencia de las entidades, estos objetos no tienen identidad propia y su principal función es agrupar datos relacionados. Un ejemplo común es una ruta que engloba un origen y un destino.

  • Herencia y relaciones: La herencia permite extender las funcionalidades de una clase base, mientras que las relaciones conectan distintas entidades y objetos para formar una red más robusta.

  • Patrones de diseño: Se utilizan para manejar estructuras complejas y promover la reutilización de código.

Estos componentes crean un sistema cohesionado donde las entidades del modelo de dominio son capaces de llevar a cabo operaciones compartidas sin sobrecargar la lógica de los servicios.

Ejemplo práctico: Modelo de dominio aplicado

Al aplicar un modelo de dominio, el ejemplo clásico es el de una entidad Flight que no solo retiene datos, como detalles del vuelo, sino que también maneja comportamientos significativos. Por ejemplo:

public class Flight {
    public int NumeroAsientosDisponibles { get; private set; }
    private List<Booking> Reservas;

    public void AgregarReservacion(Booking booking) {
        if (IsAvailable(booking.Pasajeros)) {
            Reservas.Add(booking);
            NumeroAsientosDisponibles -= booking.Pasajeros;
        }
    }

    public bool IsAvailable(int pasajeros) {
        return NumeroAsientosDisponibles >= pasajeros;
    }
}

Aquí, Flight maneja sus propias reservaciones y valida la disponibilidad de asientos internamente. Esto no solo simplifica el propósito del objeto, sino que le otorga un alcance más significativo comparado con un enfoque centrado únicamente en la transacción.

¿Cómo se impactan los servicios con el modelo de dominio?

La adopción de un modelo de dominio impacta positivamente en la capa de servicios de la aplicación. Los servicios, que anteriormente podrían tener lógica redundante en la labor de validaciones y comportamientos, ahora delegan estas responsabilidades a los objetos pertinentes del dominio. Así, las operaciones como la validación de una ruta o la verificación de la disponibilidad de un vuelo ahora se gestionan directamente dentro de los objetos de dominio, dejando que los servicios se enfoquen en coordinar más que en validar.

En camino a optimizar aún más el código, este enfoque permite que los objetos sean reutilizados en diferentes contextos sin la necesidad de duplicar lógica en diferentes partes de la aplicación. Este principio no solo mejora la mantenibilidad, sino que también agiliza el desarrollo y la extensión del software.