2011-12-06 26 views
5

Mi lenguaje de programación es C#. Tengo una pregunta sobre la ignorancia de la persistencia dentro de mi modelo de dominio.Persistente ignorante Capa de dominio

Supongamos que tengo una clase de persona, así:

public class Person 
{ 
    private string email; 

    public string Email 
    { 
     get { return email; } 
     set { email = value; } 
    } 

    public Person(string email) 
    { 
     this.email = email; 
    } 
} 

Ahora, dentro de mi modelo de dominio, hay una regla que no puede haber dos personas que tengan la misma dirección de correo electrónico. Por lo tanto, al crear una instancia de una nueva persona, debe validarse así como también al cambiar la propiedad del correo electrónico. Así que me preguntaba cómo resolverías esa validación dentro de tu capa de dominio ignorante de persistencia. Lo que hago actualmente es usar un patrón de fábrica para la creación de instancias de personas en el que inyecte un repositorio de personas. Allí puedo buscar a otra persona con la misma dirección de correo electrónico. De este modo:

public class PersonFactory 
{ 
    private static readonly IPersonRepository personRepository; 

    public Person CreateNewPerson(string email) 
    { 
     Person personWithSameMail = personRepository.GetPersonByEmail(email); 

     if (personWithSameMail != null) 
      throw new ApplicationException("Email already exists."); 

     return new Person(email); 
    } 

    public PersonFactory(IPersonRepository personRepository) 
    { 
     this.personRepository = personRepository; 
    } 
} 

Pero el uso de esta solución, el cheque al cambiar la dirección de correo electrónico personas (que puede ser un modelo de negocio válido) todavía no está cubierta. Además, la clase Persona todavía expone un constructor público y al pasar por alto la fábrica, las personas con direcciones de correo electrónico duplicadas todavía serían posibles.

¿Alguna solución elegeant a esto?

P.S. Para todos los datos centrados en las personas: No, no quiero para validar correos electrónicos duplicados en la capa de acceso a datos;)

ACTUALIZACIÓN:

Probablemente toda esta cuestión es obsoleta de todos modos. Verificar si hay correos electrónicos duplicados en términos del contexto de un modelo de dominio siempre requerirá "algo" que tenga en cuenta a todas las personas: una raíz. El "algo" podría ser una libreta de direcciones o todo el mundo que contiene a todas las personas con direcciones de correo electrónico. Así que tal vez estoy mezclando los programadores que necesitan soluciones técnicamente elegantes para los problemas, que existe solo por la falta de un modelo de dominio completo y bien pensado. ¿Puede ser este el caso aquí? Que no solo hay una persona con una dirección de correo electrónico flotando en el espacio (hey, el espacio sería mi raíz agregada aquí;)) solo por la diversión de la existencia. Pero si esto fuera un verdadero caso comercial como una aplicación de libreta de direcciones, la libreta de direcciones sería la raíz agregada de la persona y, por lo tanto, podría verificar todas las personas en su colección interna para asegurarse de que no haya una dirección de correo electrónico duplicada.

+0

¿Por qué no hace el constructor interno y también verifica la dirección de correo electrónico al actualizar? Y no creo que sea una buena solución para dar un repositorio a una fábrica. La función de servicio que llama a la fábrica debe verificar si la dirección de correo electrónico ya existe. –

+0

@WouterdeKort: No estoy de acuerdo con su comentario: (1) Hacer interno el controlador no ayuda en nada. Todavía permite la creación de usuarios con direcciones de correo duplicadas. (2) Hacer que el método que llama a la fábrica haga el control de forma efectiva elimina esa regla comercial. Ahora depende de la persona que llama para hacer cumplir esta regla. Eso es solo un diseño API muy pobre –

+0

@DanielHilgarth Menciona explícitamente que el constructor público es un problema. Una fábrica debe construir un objeto con todas las dependencias y valores requeridos. Mezclar lógica de negocios con una fábrica es algo que llamaría mal diseño. –

Respuesta

2

No soy un experto en DDD, pero mi opinión es la siguiente.

En primer lugar, para mí, el mayor defecto en su diseño es permitir a los instaladores en la entidad. Eso significa que puede alterar el estado de su entidad sin que la raíz agregada lo sepa. Yo lo refactorizaría eliminando los setters y dejando solo establecerlo a través del constructor en la creación del objeto.

Otro punto. La entidad persona no debe hacer la validación del correo electrónico (en forma de verificar si el correo electrónico ya está utilizado o no), ya que solo puede conocer su propio estado y las entidades secundarias relacionadas si es la raíz del agregado. Entonces deberías tener una referencia al repositorio de la entidad que es para mí el mal diseño. Es por eso que has usado la fábrica, creo.

Creo que la validación primero debe ocurrir en la interfaz de usuario para fallar lo más rápido posible. Pero no es suficiente. Cuando persista su estado de dominio, debe hacer cumplir la regla de que la Persona tiene un correo electrónico único.Creo que la validación debe tener lugar en el servicio de dominio, por ejemplo, se llama PersonRegistrationService que tendría una referencia a la IPersonRepository y antes de la adición de la entidad persona a su colección de persistir, sería comprobar primero si las personas mensajes de correo electrónico es único. Si no, le informaría al usuario un error y no agregaría la entidad.

¿Qué opinas?

+0

Como entiendo por lo que sugiere, la creación de una persona debe ser de dominio interno. Y luego, habrá un servicio de registro que actúa como una cosa que valida la concesión de una persona para que incluso exista con el dominio, ¿correcto? Entonces, este servicio obtendría todas las propiedades requeridas de la persona inicial como argumentos y luego, al inyectar repositorios, podría ocuparse de "¿se permite que exista la persona con la información dada?" – Chris

+0

Creo que el servicio es en primer lugar un tipo de concepto de dominio. Sugerí el Servicio de registro porque crear la Persona desde el aire no tiene sentido para mí. Entonces, la responsabilidad de ese servicio será tomar argumentos (o incluso una entidad Person nueva que en este momento no pertenece al estado del dominio), verificar con el repositorio si el correo electrónico es único y luego agregar a la persona a su colección interna (que será conservada por ORM u otra, pero no es solo importante aquí). –

+0

Quizás otros tengan otra opinión sobre esto, pero parece razonable pasar por el servicio de dominio. De hecho, es bastante similar a su fábrica, pero la diferencia es que el servicio tiene un significado de dominio y agrega a la persona después de la validación exitosa al repositorio (que es una colección de entidades Persona que persiste) –

Cuestiones relacionadas