2008-09-16 16 views
10

Después de leer los libros de Evan y Nilsson, todavía no estoy seguro de cómo administrar el acceso a los datos en un proyecto impulsado por un dominio. ¿Deberían los métodos CRUD ser parte de los repositorios, es decir, OrderRepository.GetOrdersByCustomer (cliente) o deberían ser parte de las entidades: Customer.GetOrders(). El último enfoque parece más OO, pero distribuirá el acceso a datos para un único tipo de entidad entre múltiples objetos, es decir, Customer.GetOrders(), Invoice.GetOrders(), ShipmentBatch.GetOrders(), etc. ¿Qué hay de Insertar y actualizar?acceso a datos en DDD?

Respuesta

15

Los métodos CRUD-ish deben ser parte del Depósito ... ish. Pero creo que deberías preguntarte por qué tienes un montón de métodos CRUD. ¿Qué es lo que realmente do? ¿Para qué son realmente ? Si realmente menciona los patrones de acceso a los datos que utiliza su aplicación, creo que hace que el repositorio sea mucho más útil y evita que tenga que hacer operaciones de escopeta cuando ciertos tipos de cambios suceden a su dominio.

CustomerRepo.GetThoseWhoHaventPaidTheirBill() 

// or 

GetCustomer(new HaventPaidBillSpecification()) 

// is better than 

foreach (var customer in GetCustomer()) { 
    /* logic leaking all over the floor */ 
} 

Los métodos de tipo "Guardar" también deben ser parte del repositorio.

Si tiene raíces agregadas, esto evita que tenga una explosión de repositorio o que la lógica se extienda por todas partes: no tiene 4 x # de patrones de acceso a datos de entidades, solo los que realmente usa en el agregado raíces.

Esa es mi $ .02.

2

Incluso en una DDD, mantendría las clases y las rutinas de acceso a los datos separadas de las entidades.

Las razones son,

  1. Comprobabilidad mejora
  2. separación de las preocupaciones y el diseño modular
  3. más fácil de mantener en el largo plazo, a medida que agrega entidades, rutinas

No soy experto , Solo es mi opinión.

1

Lo molesto con la aplicación de DDD de Nilsson & P es que siempre comienza con "No haría eso en una aplicación real, pero ..." y luego sigue su ejemplo. Volver al tema: Creo que OrderRepository.GetOrdersByCustomer (cliente) es el camino a seguir, pero también hay una discusión en la lista de correo de ALT.Net (http://tech.groups.yahoo.com/group/altdotnet/) sobre DDD.

3

He hecho las dos cosas de las que está hablando. Mi enfoque preferido ahora es el método persistente ignorante (o PONO - Plain Ole '.Net Object) donde las clases de dominio solo están preocupadas por ser clases de dominio. No saben nada sobre cómo persisten o incluso si persisten. Por supuesto, tienes que ser pragmático sobre esto a veces y permitir cosas como un Id (pero incluso entonces solo uso un tipo super de capa que tiene Id para que pueda tener un único punto donde vivo el valor predeterminado)

La razón principal de esto es que me esfuerzo por seguir el principio de responsabilidad única. Siguiendo este principio, he encontrado que mi código es mucho más comprobable y fácil de mantener. También es mucho más fácil hacer cambios cuando son necesarios ya que solo tengo una cosa en que pensar.

Una cosa de la que hay que estar pendiente es el método de abatimiento que pueden sufrir los repositorios. GetOrderbyCustomer .. GetAllOrders .. GetOrders30DaysOld .. etc etc. Una buena solución a este problema es observar el patrón Query Object. Y luego sus repositorios pueden simplemente tomar un objeto de consulta para ejecutar.

También recomendaría encarecidamente algo como NHibernate. Incluye muchos de los conceptos que hacen que los repositorios sean tan útiles (Identity Map, Cache, Query objects ...)

5

DDD suele preferir el patrón de repositorio sobre el patrón de registro activo al que insinúa con Customer.Save.

Una desventaja en el modelo de registro activo es que casi presume un modelo de persistencia único, salvo algún código particularmente intrusivo (en la mayoría de los idiomas).

La interfaz del repositorio se define en la capa de dominio, pero no sabe si sus datos están almacenados en una base de datos o no. Con el patrón de repositorio, puedo crear un InMemoryRepository para poder probar la lógica de dominio de forma aislada y usar la inyección de dependencia en la aplicación para que la capa de servicio cree una instancia de un SqlRepository, por ejemplo.

Para muchas personas, tener un repositorio especial solo para probar los sonidos es ridículo, pero si utiliza el modelo de repositorio, puede descubrir que realmente no necesita una base de datos para su aplicación en particular; a veces un simple FileRepository hará el truco. Casarse contigo mismo en una base de datos antes de saber que lo necesitas es potencialmente limitante. Incluso si se necesita una base de datos, es mucho más rápido ejecutar pruebas en un InMemoryRepository.

Si no tiene mucho en el camino de la lógica de dominio, es probable que no necesite DDD. ActiveRecord es bastante adecuado para muchos problemas, especialmente si tiene datos en su mayoría y solo un poco de lógica.

4

Retrocedamos por un segundo. Evans recomienda que los repositorios devuelvan raíces agregadas y no solo entidades. Entonces, suponiendo que su Cliente sea una raíz agregada que incluya Órdenes, entonces cuando recogió al cliente de su repositorio, las órdenes llegaron junto con él. Tendrás acceso a las órdenes navegando por la relación entre el Cliente y las Órdenes.

customer.Orders; 

Para responder a su pregunta, las operaciones CRUD están presentes en los repositorios raíz agregados.

CustomerRepository.Add(customer); 
CustomerRepository.Get(customerID); 
CustomerRepository.Save(customer); 
CustomerRepository.Delete(customer);