2009-03-04 3 views
20

Ho letto alcune delle domande relative ai modelli di dominio anemico e alla separazione delle preoccupazioni. Quali sono le migliori tecniche per eseguire/allegare la logica di dominio su oggetti di dominio anemici? Nel mio lavoro, abbiamo un modello piuttosto anemico e al momento utilizziamo classi "helper" per eseguire la logica del database/business sugli oggetti del dominio. Per esempio:Tecniche per gestire il modello di dominio anemico

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. 
    } 
} 

Quando l'applicazione ha bisogno di fare un acquisto, si creerebbe la StoreHelper, e chiamare il metodo sugli oggetti di dominio. Per me, sarebbe logico che il Cliente/Prodotto sapesse come salvarsi in un repository, ma probabilmente non vorresti i metodi Save() sugli oggetti del dominio. Avrebbe anche senso per un metodo come Customer.Purchase (Product), ma ciò sta mettendo la logica del dominio sull'entità.

Ecco alcune tecniche che ho incontrato, non è sicuro che sono buono/cattivo:

  1. cliente e del prodotto ereditare da una classe di "Entity", che fornisce le operazioni CRUD di base in maniera generica (usando un ORM forse).
    • Pro: Ogni oggetto di dati sarebbe automaticamente ottenere le operazioni CRUD, ma vengono poi legato al database/ORM
    • Contro: Questo non risolve il problema delle operazioni di business sugli oggetti, e lega anche tutti gli oggetti di dominio a un'entità di base che potrebbe non essere appropriato
  2. classi Usa helper per gestire le operazioni CRUD e la logica di business
    • ha senso avere DAO per le operazioni di "pure database", e aiutanti di business separate per loro O operazioni commerciali specifiche?
    • È meglio utilizzare classi di helper statiche o non statiche per questo?
    • Pro: oggetti di dominio non sono legati a qualsiasi logica di database/incassi (completamente anemica)
    • Contro: non molto OO, non molto naturale da usare soccorritori in codice dell'applicazione (si presenta come codice C)
  3. utilizzare la tecnica doppio spedizione in cui le entità ha metodi per salvare un repository arbitrario
    • Pro: migliore separazione tra gli
    • Contro: entità hanno una logica supplementare divisoria (anche se è disaccoppiato)
  4. In C# 3.0, è possibile utilizzare metodi di estensione per collegare i metodi CRUD/azienda a un oggetto di dominio senza toccarlo
    • Si tratta di un valido approccio? Cosa sono i pro/contro?
  5. Altre tecniche?

Quali sono le migliori tecniche per gestirlo? Sono abbastanza nuovo di DDD (sto leggendo il libro di Evans - quindi forse aprirò gli occhi)

risposta

7

Martin Fowler ha scritto molto su modelli di dominio, tra cui anemic domain models. Ha anche una breve descrizione (e diagrammi di classe UML) di molti modelli di progettazione per i modelli di dominio e basi di dati che potrebbero essere utili: Catalog of "Patterns of Enterprise Application Architecture".

vorrei suggerire a guardare i modelli Active Record e Data Mapper. Dalla descrizione del problema, suona come le vostre classi helper contengono sia le regole di dominio/aziendali e dettagli di implementazione del database.

Il record attivo sposta la logica del dominio dell'helper e il codice del database negli altri oggetti dominio (come la classe base Entity). Il Data Mapper sposterebbe la logica del dominio dell'helper negli oggetti del dominio e il codice del database in un oggetto mappa separato. Entrambi gli approcci sarebbero più orientati agli oggetti rispetto alle classi helper in stile procedurale.

Eric Evans' libro "Domain Driven Design" è eccellente. Diventa un po 'asciutto, ma ne vale la pena. InfoQ ha un "Domain Driven Design Quickly" mini-book che è una buona introduzione al libro di Evans. Inoltre, "Domain Driven Design Quickly" è disponibile come PDF gratuito.

2

Ho sempre pensato al modello di dominio anemico come a un modello anti.E 'chiaro che un cliente acquisterà prodotti, che la capacità può essere generised da un'implementazione dell'interfaccia

Interface IPurchase 
     Purchase(Product); 

, quindi una qualsiasi dei vostri oggetti del dominio può quindi implementare che, come richiesto. In questo modo puoi introdurre funzionalità per i tuoi oggetti di dominio, che è esattamente dove dovrebbe essere.

14

Al fine di evitare il modello anemico, riconfigurare le classi di supporto:

Logica come:
"Customer.PurchaseProduct (prodotto, Pagamento pagamento)",
"Customer.KillCustomer (persona assassino, arma arma) "
deve esistere direttamente nell'oggetto dominio" Cliente ".

Logica come:
"Customer.IsCustomerAlive()"
"Customer.IsCustomerHappy()"
dovrebbe andare alle specifiche.

Logica come:
"Customer.Create()",
"Customer.Update()"
ovviamente dovrebbe andare a repository.

Logica come:
"Customer.SerializeInXml()"
"Customer.GetSerializedCustomerSizeInBytes()"
dovrebbe andare ai servizi.

costruttori complessi dovrebbero andare alle fabbriche.

Ecco come lo vedo. Sarei felice se qualcuno potesse commentare la mia comprensione dell'approccio DDD.


Edit:

A volte - modello anemica dominio shouldn't be avoided.

Modificata la mia risposta per aggiungere che DDD non riguarda il ritiro e il rilascio di modelli.
DDD è circa il modo in cui pensiamo.

+0

Sembra un sacco di classi diverse solo per gestire un cliente. Perché non buttare la maggior parte di esso in una singola classe, con un servizio per gestire qualcosa di complesso? –

+0

La mia risposta è vecchia come l'inferno. : D –

+0

@LuckyLindy Principalmente perché DDD sta creando un ponte tra esperti di dominio e programmatori. Il modello di dominio non dovrebbe contenere materiale tecnico, altrimenti il ​​linguaggio onnipresente non potrà esistere. Per uscire dalla roba tecnica - dobbiamo astrarla. L'astrazione di qualcosa gonfia sempre la base di codice. –

0

Un approccio che non è stato menzionato sta utilizzando AOP per gestire l'accesso ai dati. Un esempio del mio recente utilizzo di questo approccio (anche se molto semplificato per scopi di pubblicazione) era che avevo un'entità di dominio Account che aveva un metodo debit, che incapsula la logica di business richiesta per fare un addebito riuscito dall'account.

N.B. Tutto il codice è Java con AspectJ AOP notazione ...

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

con il repository appropriato iniettato nel mio aspetto, Ho quindi utilizzato un pointcut per intercettare le chiamate a questo metodo ...

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

. ..e applicato alcuni consigli:

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

a mio parere questo dà un bel separazione degli interessi, e permette ai soggetti dominio di concentrarsi interamente sulla logica di business di y la nostra applicazione.