tutorial significado por impulsado implementing guiado español driven dominio domain diseño ddd code clean domain-driven-design business-logic

domain driven design - significado - Técnicas para tratar el modelo de dominio anémico.



domain driven design tutorial (4)

Martin Fowler ha escrito mucho sobre los modelos de dominio, incluidos los modelos de dominio anémico . También tiene descripciones breves (y diagramas de clase UML) de muchos patrones de diseño para modelos de dominio y bases de datos que podrían ser útiles: Catálogo de "Patrones de arquitectura de aplicaciones empresariales" .

Sugeriría mirar los patrones Active Record y Data Mapper . A partir de la descripción de su problema, parece que las clases de su ayudante contienen tanto las reglas de dominio / negocio como los detalles de implementación de la base de datos.

El registro activo movería la lógica del dominio del ayudante y el código de la base de datos a los otros objetos del dominio (como la clase base de la Entity ). El asignador de datos movería la lógica del dominio del ayudante a los objetos del dominio y el código de la base de datos a un objeto de mapa separado. Cualquiera de los dos enfoques estaría más orientado a objetos que las clases auxiliares de estilo de procedimiento.

El libro "Diseño dirigido por dominio" de Eric Evans es excelente. Se seca un poco, pero definitivamente vale la pena. InfoQ tiene un mini-libro "Diseño dirigido por dominio rápidamente" que es una buena introducción al libro de Evans. Además, "Domain Driven Design Quickly" está disponible como PDF gratuito.

He leído algunas de las preguntas sobre los modelos de dominio anémico y la separación de inquietudes. ¿Cuáles son las mejores técnicas para realizar / adjuntar lógica de dominio en objetos de dominio anémicos? En mi trabajo, tenemos un modelo bastante anémico y actualmente estamos usando clases "auxiliares" para realizar la base de datos / lógica empresarial en los objetos del dominio. Por ejemplo:

public class Customer { public string Name {get;set;} public string Address {get;set;} } public class Product { public string Name {get;set;} public decimal Price {get;set;} } public class StoreHelper { public void PurchaseProduct(Customer c, Product p) { // Lookup Customer and Product in db // Create records for purchase // etc. } }

Cuando la aplicación necesita realizar una compra, creará StoreHelper y llamará al método en los objetos del dominio. Para mí, tendría sentido que el Cliente / Producto supiera cómo guardarse en un repositorio, pero probablemente no querría los métodos Save () en los objetos del dominio. También tendría sentido para un método como Customer.Purchase (Producto), pero eso es poner lógica de dominio en la entidad.

Aquí hay algunas técnicas que he encontrado, no estoy seguro de cuáles son buenas / malas:

  1. El Cliente y el Producto heredan de una clase de "Entidad", que proporciona las operaciones básicas de CRUD de una manera genérica (utilizando un ORM, tal vez).
    • Pros: Cada objeto de datos obtendría automáticamente las operaciones CRUD, pero luego se vincularán a la base de datos / ORM
    • Contras: esto no resuelve el problema de las operaciones comerciales en los objetos y también vincula todos los objetos de dominio a una Entidad base que podría no ser apropiada
  2. Use clases de ayuda para manejar las operaciones de CRUD y la lógica de negocios
    • ¿Tiene sentido tener DAO para las operaciones de "base de datos pura" y separar a los ayudantes de negocios para las operaciones más específicas del negocio?
    • ¿Es mejor usar clases de ayuda no estáticas o estáticas para esto?
    • Pros: los objetos de dominio no están vinculados a ninguna base de datos / lógica empresarial (completamente anémica)
    • Contras: no muy OO, no es muy natural utilizar ayudantes en el código de la aplicación (parece el código C)
  3. Utilice la técnica de doble envío donde la entidad tiene métodos para guardar en un repositorio arbitrario
    • Pros: mejor separación de preocupaciones
    • Contras: las entidades tienen una lógica extra adjunta (aunque está desacoplada)
  4. En C # 3.0, podría usar métodos de extensión para adjuntar los métodos de CRUD / negocio a un objeto de dominio sin tocarlo
    • ¿Es este un enfoque válido? ¿Qué son los pros / contras?
  5. Otras tecnicas?

¿Cuáles son las mejores técnicas para manejar esto? Soy bastante nuevo en DDD (estoy leyendo el libro de Evans, así que tal vez eso abra mis ojos)


Para evitar el modelo anémico, refactorice sus clases de ayudante:

Lógica como:
"Cliente.CompraProducto (producto del producto, pago del pago)",
"Customer.KillCustomer (Person killer, Weapon armas)"
debe existir directamente en el objeto de dominio "Cliente".

Lógica como:
"Customer.IsCustomerAlive ()"
"Customer.IsCustomerHappy ()"
Debe ir a las especificaciones.

Lógica como:
"Cliente.Crear ()",
"Customer.Update ()"
Obviamente hay que ir a los repositorios.

Lógica como:
"Customer.SerializeInXml ()"
"Customer.GetSerializedCustomerSizeInBytes ()"
Debe ir a los servicios.

Los constructores complejos deben ir a las fábricas.

Así es como lo veo. Me alegraría si alguien pudiera comentar mi comprensión del enfoque de DDD.

Editar:

A veces, el modelo de dominio anémico no debe evitarse .

Edité mi respuesta para agregar que DDD no se trata de recoger y soltar patrones.
DDD es sobre cómo pensamos.


Siempre he pensado en el modelo de dominio anémico como un patrón anti. Está claro que un cliente comprará productos, esa capacidad puede generarse mediante una implementación de interfaz

Interface IPurchase Purchase(Product);

, por lo que cualquiera de los objetos de su dominio puede implementarlo según sea necesario. De esa manera, puede introducir funcionalidad en los objetos de su dominio, que es exactamente donde debería estar.


Un enfoque que no ha mencionado es usar AOP para manejar su acceso a los datos. Un ejemplo de mi uso reciente de este enfoque (aunque muy simplificado para propósitos de publicación) fue que tenía una entidad de dominio de Account que tenía un método de debit , que encapsulaba la lógica de negocios requerida para hacer un débito exitoso de la cuenta.

NB Todo el código es Java con notación AspectJ AOP ...

public boolean debit(int amount) { if (balance - amount >= 0) { balance = balance - amount; return true; } return false; }

Con el repositorio apropiado inyectado en mi aspecto, utilicé un corte de punto para interceptar llamadas a este método ...

pointcut debit(Account account,int amount) : execution(boolean Account.debit(int)) && args(amount) && target(account);

... y apliqué algunos consejos:

after(Account account, int amount) returning (boolean result) : debit(account,amount) { if (result) getAccountRepository().debit(account, amount); }

En mi opinión, esto proporciona una buena separación de inquietudes y permite que las entidades de su dominio se centren por completo en la lógica de negocios de su aplicación.