2010-02-09 27 views
7

Introzione noiosa:DDD, gestione delle dipendenze

So che - DDD non riguarda la tecnologia. Per come la vedo io, DDD si occupa di creare un linguaggio ubiquo con il proprietario del prodotto e di rifletterlo in codice in modo così semplice e strutturato, che non può essere interpretato erroneamente o perso.

Ma ecco che entra in gioco un paradosso: per liberarsi del lato tecnico dell'applicazione nel modello di dominio, diventa un po 'tecnico - almeno dal punto di vista del design.

L'ultima volta che ho provato a seguire DDD - è finito con tutta la logica al di fuori degli oggetti di dominio in servizi "magici" tutt'intorno e un modello di dominio anemico.

Ho imparato alcuni nuovi trucchi ninja e mi chiedo se potrei gestire Goliath questa volta.


Problema:

class store : aggregateRoot { 
    products; 
    addProduct(product){ 
    if (new FreshSpecification.IsSatisfiedBy(product)) 
     products.add(product); 
    } 
} 

class product : entity { 
    productType; 
    date producedOn; 
} 

class productTypeValidityTerm : aggregateRoot { 
    productType; 
    days; 
} 

FreshSpecification si suppone di specificare se il prodotto non puzza. Per fare ciò, dovrebbe controllare il tipo di prodotto, trovare da esso il tempo in cui il prodotto è fresco e confrontarlo con producedOn. Gentile un semplice.

Ma ecco che arriva il problema - productTypeValidityTerm e productType devono essere gestiti dal cliente. Dovrebbe essere in grado di aggiungerli/modificarli liberamente. Poiché non posso attraversare direttamente dal prodotto a productTypeValidityTerm, ho bisogno di interrogarli in qualche modo entro il productType.

In precedenza, creerei qualcosa come ProductService che riceve i necessari repository tramite il costruttore, termini di query, esegue un ulteriore voodoo e restituisce booleano (prendendo la logica pertinente più lontano dall'oggetto stesso e diffondendolo chissà dove).

ho pensato che potrebbe essere accettabile per fare qualcosa di simile:

addProduct(product, productTypeValidityTermRepository){...} 

Ma poi di nuovo - non ho potuto comporre specifiche da più specifiche sotto liberamente ciò che è uno dei loro principali vantaggi.

Quindi - la domanda è, dove farlo? In che modo il negozio può essere a conoscenza dei termini?

+1

+1 Buona domanda. Sono ancora alle prese con questo, ma ecco un tentativo precedente di rispondere a qualcosa di simile: http://stackoverflow.com/questions/1264944/refactoring-domain-logic-that-accesses-repositories-in-a-legacy-system/1265055 # 1265055 –

risposta

2

Con il rischio di semplificare eccessivamente le cose: perché non rendere il fatto se uno Product è fresco qualcosa che un prodotto "sa"? Un Store (o qualsiasi altro tipo di oggetto correlato) non dovrebbe sapere come determinare se un prodotto è ancora fresco; in altre parole, il fatto che esistano ancora qualcosa come freshSpecification o productTypeValidityTerm non dovrebbe essere noto a Store, dovrebbe semplicemente controllare Product.IsFresh (o forse qualche altro nome che si allinea meglio con il mondo reale, come ShouldbeSoldBy, ExpiresAfter, ecc.). Il prodotto potrebbe quindi sapere come recuperare effettivamente lo protductTypeValidityTerm iniettando la dipendenza dal repository.

Mi sembra che stiate esternalizzando un comportamento che dovrebbe essere intrinseco agli aggregati/entità del vostro dominio, portando infine (di nuovo) a un modello di dominio anemico.

Ovviamente, in uno scenario più complicato, in cui la freschezza dipende dal contesto (ad es., ciò che è accettabile in un negozio a basso costo non è considerato degno di vendita in un punto vendita premium) è necessario esternalizzare l'intero comportamento, sia dal prodotto che dal negozio, e creare un tipo diverso per modellare questo particolare comportamento.

Aggiunto dopo il commento

Qualcosa in questo senso per il semplice scenario che ho citato: fare la parte FreshSpec dell'aggregato del prodotto, che permette al ProductRepository (costruttore-iniettato qui) a (pigro) caricare quando necessario.

public class Product { 
    public ProductType ProductType { get; set; } 
    public DateTime ProducedOn { get; set; } 
    private FreshSpecification FreshSpecification { get; set; } 
    public Product(IProductRepository productRepository) { } 

    public bool IsFresh() { 
    return FreshSpecification 
     .IsSatisfiedBy(ProductType, ProducedOn); 
    } 
} 

Il negozio non conosce questi interni: tutto quello che preoccupa è se il prodotto è fresco:

public class Store { 
    private List<Product> Products = new List<Product>(); 
    public void AddProduct(Product product) { 
    if (product.IsFresh()) { 
     Products.Add(product); 
    } 
    } 
} 
+0

Ho pensato anche a questo - che sto solo modellando questo sbagliato. Sarei felice di accettare la tua risposta se potessi riscrivere il mio pseudo-codice per riflettere la tua idea. –

+0

@tijmenvdk Quindi - va bene iniettare il repository del prodotto nell'oggetto del prodotto, giusto? Da qualche parte ho letto che dovrebbe essere evitato (d'altra parte, sembra abbastanza ragionevole). –

+0

Quindi, fondamentalmente, le entità potrebbero essere confrontate un po 'con quelle ben note del vecchio 'ProductManager', ma con tutto il lato tecnico spogliato e modellato in modo più accurato e accurato. È giusto? –

Problemi correlati