Domanda

Dopo aver letto i libri di Evan e Nilsson, non sono ancora sicuro di come gestire l'accesso ai dati in un progetto basato su dominio.I metodi CRUD dovrebbero far parte dei repository, ad es.OrderRepository.GetOrdersByCustomer(customer) o dovrebbero far parte delle entità:Cliente.GetOrders().Quest'ultimo approccio sembra più OO, ma distribuirà l'accesso ai dati per un singolo tipo di entità tra più oggetti, ad es.Customer.GetOrders(), Invoice.GetOrders(), ShipmentBatch.GetOrders(), ecc.E per quanto riguarda l'inserimento e l'aggiornamento?

È stato utile?

Soluzione

I metodi CRUD dovrebbero far parte del repository... più o meno.Ma penso che dovresti chiederti perché hai un sacco di metodi CRUD.Cosa fanno loro Veramente Fare?Quali sono Veramente per?Se effettivamente richiami i modelli di accesso ai dati utilizzati dalla tua applicazione, penso che renda il repository molto più utile e ti impedisca di dover fare un intervento chirurgico quando si verificano determinati tipi di modifiche al tuo dominio.

CustomerRepo.GetThoseWhoHaventPaidTheirBill()

// or

GetCustomer(new HaventPaidBillSpecification())

// is better than

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

Anche i metodi di tipo "Salva" dovrebbero far parte del repository.

Se hai radici aggregate, questo ti impedisce di avere un'esplosione del repository o di avere una logica diffusa ovunque:Non hai 4 x # di modelli di accesso ai dati delle entità, solo quelli che usi effettivamente sulle radici aggregate.

Questi sono i miei $ 0,02.

Altri suggerimenti

DDD di solito preferisce il modello di repository rispetto al modello di record attivo suggerito con Customer.Save.

Uno svantaggio del modello Active Record è che presuppone praticamente un singolo modello di persistenza, salvo qualche codice particolarmente intrusivo (nella maggior parte dei linguaggi).

L'interfaccia del repository è definita nel livello del dominio, ma non sa se i tuoi dati sono archiviati o meno in un database.Con il modello di repository, posso creare un InMemoryRepository in modo da poter testare la logica del dominio in isolamento e utilizzare l'inserimento delle dipendenze nell'applicazione per fare in modo che il livello di servizio istanzia un SqlRepository, ad esempio.

Per molte persone, avere un repository speciale solo per testare sembra sciocco, ma se usi il modello del repository, potresti scoprire che non hai realmente bisogno di un database per la tua particolare applicazione;a volte un semplice FileRepository farà al caso tuo.Matrimoniare te stesso con un database prima di sapere di averne bisogno è potenzialmente limitante.Anche se è necessario un database, è molto più veloce eseguire test su InMemoryRepository.

Se non hai molto in termini di logica del dominio, probabilmente non hai bisogno di DDD.ActiveRecord è abbastanza adatto per molti problemi, soprattutto se hai principalmente dati e solo un po' di logica.

Facciamo un passo indietro per un secondo.Evans consiglia che i repository restituiscano radici aggregate e non solo entità.Quindi, supponendo che il tuo cliente sia una radice aggregata che include ordini, quando hai recuperato il cliente dal suo repository, gli ordini sono arrivati ​​insieme ad esso.Potrai accedere agli ordini navigando nella relazione da Cliente a Ordini.

customer.Orders;

Quindi, per rispondere alla tua domanda, le operazioni CRUD sono presenti nei repository root aggregati.

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

L'ho fatto in entrambi i modi di cui parli. Il mio approccio preferito ora è il metodo persistent ignorant (o PONO - Plain Ole' .Net Object) in cui le tue classi di dominio si preoccupano solo di essere classi di dominio.Non sanno nulla di come vengono persistenti e nemmeno se vengono persistenti.Ovviamente a volte devi essere pragmatico al riguardo e consentire cose come un Id (ma anche in questo caso utilizzo semplicemente un super tipo di livello che ha l'Id in modo da poter avere un singolo punto in cui risiedono cose come il valore predefinito)

La ragione principale di ciò è che mi sforzo di seguire il principio della responsabilità unica.Seguendo questo principio ho trovato il mio codice molto più testabile e manutenibile.È anche molto più semplice apportare modifiche quando necessario poiché ho solo una cosa a cui pensare.

Una cosa a cui prestare attenzione è il gonfiore del metodo di cui possono soffrire i repository.Ottieniordinepercliente..Ottieni tutti gli ordini..Ottieni ordini30GiorniVecchi..ecc ecc.Una buona soluzione a questo problema è osservare il modello Query Object.E quindi i tuoi repository possono semplicemente accogliere un oggetto query da eseguire.

Consiglio vivamente anche di esaminare qualcosa come NHibernate.Include molti concetti che rendono i repository così utili (mappa identità, cache, oggetti query...)

Anche in un DDD, manterrei le classi e le routine di accesso ai dati separate dalle entità.

Le ragioni sono,

  1. La testabilità migliora
  2. Separazione degli interessi e progettazione modulare
  3. Più gestibile a lungo termine, aggiungendo entità e routine

Non sono un esperto, solo la mia opinione.

La cosa fastidiosa dell'applicazione DDD&P di Nilsson è che inizia sempre con "Non lo farei in un'applicazione nel mondo reale ma..." e poi segue il suo esempio.Torniamo all'argomento:Penso che OrderRepository.GetOrdersByCustomer(customer) sia la strada da percorrere, ma c'è anche una discussione sulla mailing list ALT.Net (http://tech.groups.yahoo.com/group/altdotnet/) su DDD.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top