2009-03-04 18 views
20

He leído algunas de las preguntas sobre los modelos de dominio anémico y la separación de las preocupaciones. ¿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 de "ayuda" para realizar la lógica de la base de datos/negocios en los objetos del dominio. Por ejemplo:Técnicas para tratar el modelo de dominio anémico

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 tiene que hacer una compra, que crearía la StoreHelper, y llame al método de los objetos de dominio. Para mí, tendría sentido que el Cliente/Producto supiera cómo guardarse en un repositorio, pero probablemente no desee los métodos Save() en los objetos del dominio. También tendría sentido para un método como Customer.Purchase (Product), pero eso es poner lógica de dominio en la entidad.

Estas son algunas de las técnicas que he encontrado, no estoy seguro, que son bueno/malo:

  1. cliente y producto heredan de una clase de "Entidad", que proporciona las operaciones CRUD básicas de una forma genérica (usando un ORM tal vez).
    • Pros: Cada objeto de datos recibirá automáticamente las operaciones CRUD, pero luego se atan a la base de datos/ORM
    • Contras: Esto no resuelve el problema de las operaciones comerciales en los objetos, y también se vincula todos los objetos de dominio a una entidad de base que podría no ser apropiada
  2. clases de uso auxiliar para manejar las operaciones CRUD y la lógica de negocio
    • ¿tiene sentido tener DAOs para las "bases de datos puros" operaciones y ayudantes de negocio independientes para ellos ¿operaciones comerciales específicas del mineral?
    • ¿Es mejor utilizar clases auxiliares no estáticas o estáticas para esto?
    • Pros: objetos de dominio no están vinculados a ninguna lógica de la base de datos/negocio (completamente anémica)
    • Contras: no es muy OO, no muy natural utilizar ayudantes en el código de aplicación (se parece a código C)
  3. utilice la técnica de doble Despacho, donde la entidad tiene métodos para salvar a un repositorio arbitraria
    • Pros: mejor separación de las
    • Contras: las entidades tienen cierta lógica adicional adjunto (aunque está desacoplado)
  4. En C# 3.0, puede utilizar los métodos de extensión para unir los métodos CRUD/negocio a un objeto de dominio sin tocarlo
    • Es este un enfoque válido? ¿Cuáles son los pros/contras?
  5. ¿Otras técnicas?

¿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 me abra los ojos)

Respuesta

7

Martin Fowler ha escrito mucho sobre los modelos de dominio, incluido anemic domain models. 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 pueden ser útiles: Catalog of "Patterns of Enterprise Application Architecture".

Sugeriría mirar los patrones Active Record y Data Mapper. Según la descripción de su problema, parece que sus clases de ayuda contienen las reglas de dominio/negocio y detalles de implementación de la base de datos.

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

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

2

Siempre he pensado en el modelo de dominio anémico como un patrón anti.Está claro que un cliente va a comprar productos, que la capacidad se puede generised por una implementación de la interfaz

Interface IPurchase 
     Purchase(Product); 

, por lo que una cualquiera de sus objetos de dominio a continuación, puede aplicar que a medida que sea necesario. De esa forma, puede introducir funcionalidad en sus objetos de dominio, que es exactamente donde debería estar.

14

Con el fin de evitar el modelo de anemia, refactorizar sus clases de ayuda:

lógica como:
"Customer.PurchaseProduct (producto, el pago de pago)",
"Customer.KillCustomer (asesino persona, armas Arma) "
debe existir en el objeto de dominio" Cliente ".

lógica como:
"Customer.IsCustomerAlive()"
"Customer.IsCustomerHappy()"
debería ir a las especificaciones.

lógica como:
"Customer.Create()",
"Customer.Update()"
, obviamente, debe 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 DDD.


Editar:

veces - modelo de dominio anémico shouldn't be avoided.

Edité mi respuesta para agregar que DDD no se trata de recoger y soltar patrones.
DDD es sobre nuestra forma de pensar.

+0

Parece un montón de diferentes clases solo para manejar un cliente. ¿Por qué no lanzar la mayor parte en una sola clase, con un servicio para manejar cualquier cosa compleja? –

+0

Mi respuesta es vieja como el infierno. : D –

+0

@LuckyLindy Principalmente porque DDD se trata de crear un puente entre expertos de dominio y programadores. El modelo de dominio no debe contener material técnico, de lo contrario el lenguaje ubicuo no podrá existir. Para mover cosas técnicas, debemos abstraerlo. Resumiendo algo siempre se infla la base de códigos. –

0

Un enfoque que no ha mencionado es el uso de AOP para gestionar su acceso a los datos. Un ejemplo de mi uso reciente de este enfoque (aunque muy simplificado para fines de publicación) fue que tenía una entidad de dominio Account que tenía un método debit, que encapsulaba la lógica empresarial necesaria para realizar un débito exitoso desde la cuenta.

N.B. Todo el código es Java con la notación AspectJ AOP ...

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

Con el repositorio adecuado inyectado en mi aspecto, a continuación, he utilizado un punto de corte para interceptar las llamadas a este método ...

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

. ..y aplicado un consejo:

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

en mi opinión, esto da una buena separación de intereses, y permite que sus entidades de dominio para centrarse exclusivamente en la lógica de negocio de y nuestra aplicación.

Cuestiones relacionadas