2011-01-29 15 views
5

Nel tentativo di comprendere Domain Driven Design continuo a tornare a una domanda a cui non riesco a dare una risposta definitiva.Quando la logica appartiene all'oggetto/entità aziendale e quando appartiene a un servizio?

Come si determina quale logica appartiene a un'entità di dominio e quale logica appartiene a un servizio di dominio?

Esempio: Abbiamo una classe di ordine per un negozio online. Questa classe è un'entità e una radice aggregata (contiene OrderItem).

Public Class Order:IOrder 
{ 
    Private List<IOrderItem> OrderItems 

    Public Order(List<IOrderItem>) 
    { 
     OrderItems = List<IOrderItem> 
    } 

    Public Decimal CalculateTotalItemWeight() 
    //This logic seems to belong in the entity. 
    { 
     Decimal TotalWeight = 0 
     foreach(IOrderItem OrderItem in OrderItems) 
     { 
      TotalWeight += OrderItem.Weight 
     } 
     return TotalWeight 

    } 
} 

penso che la maggior parte delle persone sarebbe d'accordo che CalculateTotalItemWeight appartiene sull'entità. Tuttavia, a un certo punto dobbiamo spedire questo ordine al cliente. Per fare ciò, dobbiamo fare due cose:

1) Determinare la velocità di spedizione necessaria per spedire questo ordine.

2) Stampare un'etichetta di spedizione dopo aver determinato la velocità di spedizione.

Entrambe queste azioni richiedono dipendenze esterne all'entità Ordine, ad esempio un servizio Web esterno per il recupero delle tariffe postali. Come dovremmo realizzare queste due cose? Vedo alcune opzioni:

1) Codificare la logica direttamente nell'entità di dominio, ad esempio CalculateTotalItemWeight. Chiamiamo quindi:

Order.GetPostageRate 
Order.PrintLabel 

2) Inserire la logica in un servizio che accetta IOrder. Abbiamo poi chiamiamo:

PostageService.GetPostageRate(Order) 
PrintService.PrintLabel(Order) 

3) Creare una classe per ogni azione che opera su un Ordine, e passiamo un'istanza di tale classe per l'Ordine attraverso Costruttore Injection (questa è una variante dell'opzione 1, ma permette il riutilizzo di le classi RateRetriever e Labelprinter):

Public Class Order:IOrder 
{ 
    Private List<IOrderItem> OrderItems 
    Private RateRetriever _Retriever 
    Private LabelPrinter _Printer 

    Public Order(List<IOrderItem>, RateRetriever Retriever, LabelPrinter Printer) 
    { 
     OrderItems = List<IOrderItem> 
     _Retriever = Retriever 
     _Printer = Printer 
    } 

    Public Decimal GetPostageRate 
    { 
     _Retriever.GetPostageRate(this) 
    } 

    Public void PrintLabel 
    { 
     _Printer.PrintLabel(this) 
    } 
} 

Quale di questi metodi si fa a scegliere per questa logica, se del caso? Qual è il ragionamento dietro la tua scelta? Ancora più importante, c'è una serie di linee guida che ti hanno portato alla tua scelta?

+1

un Ordine difficilmente può essere agnostico sui suoi elementi OrderDetail ... era quello che volevi dire? –

risposta

1

Tenderei ad avere un servizio esterno per determinare la tariffa di spedizione. Per me questa è logica applicativa piuttosto che logica specifica per ordine. Ad esempio, potresti decidere per un periodo di offrire la spedizione gratuita per ordini superiori a una certa dimensione o per un gruppo particolare di clienti fedeli. Per me quella logica tenderà a cambiare indipendentemente da come viene costruito un ordine.

Molto probabilmente avrei il codice che è responsabile per l'inoltro dell'ordine (una sorta di servizio Processore ordini, in un livello applicazione o in un gestore comandi) consegnare a un servizio per ottenere la velocità di spedizione e quindi passare tale tariffa nell'ordine, quindi suppongo opzione 2.

Per stampare un'etichetta di spedizione, tenderei ad avere il dominio di generare un evento lungo le linee di http://www.udidahan.com/2009/06/14/domain-events-salvation/. Un gestore separato avrebbe quindi a che fare con la stampa dell'etichetta. Di nuovo, la logica di questo è che il modo in cui si stampano le etichette è probabile che varia indipendentemente da come si costruisce un ordine, quindi ha senso tenerlo separato. L'utilizzo di un evento di dominio sembra essere il modo più pulito per garantire che l'etichetta venga stampata al momento giusto senza che l'Ordine (o il processore dell'ordine) sia a conoscenza della logica di stampa.

+0

Il mio istinto è seguire la vostra linea di pensiero, ma se seguiamo questa linea di pensiero finiamo per avere un dominio anemico con tutta la nostra "vera" logica al di fuori delle nostre entità? –

+0

Anch'io mi sono preoccupato, ma non ha funzionato in questo modo. Sicuramente alcune logiche sono finite a livello di applicazione, ma in realtà penso che sia giusto comunque. – David

+0

Basta leggere nuovamente la tua domanda originale. Se stai chiamando un servizio web esterno per le tariffe di spedizione, allora quella logica è al di fuori del dominio a prescindere.Direi che è una decisione a livello di applicazione utilizzare un webservice esterno. Se ci fossero delle regole applicate alle informazioni che hai restituito - ad esempio applichi uno sconto alla tariffa per i clienti fedeli o qualcosa del genere - quella logica potrebbe essere ancora applicata nel dominio, quindi dovresti passare il risultato del servizio web di nuovo nel dominio. – David

0

Il mio punto di vista: Il dominio è ciò che contiene la logica della vostra applicazione, senza l'infrastruttura cruft. La logica è che quando un ordine viene confermato viene stampata un'etichetta e viene determinata la velocità di spedizione. Questo dovrebbe essere nel dominio.

L'infrastruttura quindi realizza ciò che il dominio vuole fare. Il dominio può consentire all'infrastruttura di conoscere tramite messaggi o eventi.

In questo modo nessuna infrastruttura perde nel dominio, è necessario solo un modo per trasportare i messaggi fuori dal dominio.

+0

Quindi useresti uno degli approcci che ho menzionato, o qualcosa di diverso? –

1

Vorrei usare (2).

Non aggiunge ulteriore complessità all'elemento dell'ordine.

Per me, sembra l'uso naturale di un servizio di supporto.

Aggiornamento: in risposta al commento: la pagina wiki stati:

anemico Domain Model: Con questo modello, la logica è tipicamente implementato in classi separate che trasformano lo stato del dominio oggetti

+0

L'utilizzo del n. 2 ci spinge verso un modello di dominio anemico secondo te? –

+0

Io non la penso così, per quanto ne so, va bene avere un oggetto separato che prende un sacco di altri oggetti e prendere decisioni in base al loro stato fintanto che gli oggetti in questione non vengono alterati o trasformati. –

+0

Se cambiamo lo stato dell'ordine facendo in modo che il servizio imposti una proprietà PostageRate sull'ordine ... Conta come trasformare l'ordine? Qualcosa di così insignificante significa che dovremmo cambiare la nostra decisione originale? Sembra che DDD sia così pieno di questi "Catch 22" che diventa molto difficile da implementare. –

1

Se si accede a servizi web esterni per ottenere Francobollo tasso, è meglio per creare l'interfaccia a livello di applicazione, perché Evan stesso ha suggerito che se si vuole parlare con webservices esterni si dovrebbe costruire l'interfaccia a livello di applicazione, si dovrebbe avere l'implementazione del servizio iniettata nell'oggetto dominio. Per stampare l'etichetta di spedizione , poiché l'etichetta viene stampata solo quando viene determinata la velocità di spedizione, quindi è un tipo di evento come PostageRateConfirmed il dominio può generare questo evento.

http://danhaywood.com/2010/04/30/accessing-domain-services-from-entities/

Problemi correlati