Le classi di dominio POCO dovrebbero contenere collezioni?

2

Il titolo della domanda non è buono, ma non potevo pensare a un modo per esprimerlo meglio.

Sono abituato a sviluppare utilizzando le classi POCO nei miei progetti, ovvero, gli oggetti di dominio non contengono assolutamente logica, solo dati.

Mi chiedo quale sia l'approccio migliore quando si ha a che fare con le relazioni di classe - per mettere una raccolta all'interno della classe o per richiederla in seguito.

Ad esempio, considera di avere un'applicazione di e-commerce, che ha Ordini e Articoli all'interno di quegli Ordini. Quindi potremmo avere (pseudo-codice)

class Order
{
     int id;
     List<OrderItem> Items;
}

class OrderItem
{
     Product product;
     int quantity;
}

E poi usalo (1)

var o = LoadOrder(id);
foreach (var i in o.Items) {

... o potremmo fare:

class Order
{
    int id;
}

E usalo in questo modo: (2)

var odr = LoadOrder(id);
var itms = LoadItemsOfOrder(odr);
foreach (var i in itms) { 
    .....

Il primo modo è più compatto e più "OOP-ish", ma il secondo modo dà più controllo su come e quando vengono richiesti gli elementi, ad es. cosa succede se ora ho bisogno di richiedere solo gli articoli che hanno quantità > 3? E se non utilizzo affatto la raccolta Articoli (ad es. Per visualizzare solo un elenco di ordini) - Farò query inutili al database.

Nei miei vecchi progetti più grandi ho seguito un approccio ibrido: le classi di dominio sono di primo livello, ma esistono vari metodi di "caricamento", come "LoadOrder" e "LoadOrderWithItems" o "FillOrderObject".

Ora sto lavorando a un piccolo progetto di giocattoli, nessun cliente e scadenze folli e ho avuto il tempo di riflettere su questi temi.

Ho provato a cercare sul Web ma è molto difficile trovare una risposta POCO non correlata a Entity Framework. (Non sto lavorando in .net questa volta, ma vorrei applicare questi concetti.)

Domanda : esiste un metodo che è chiaramente migliore rispetto all'altra, o entrambi sono validi e "dipende" dal mio progetto, se puntiamo al rendimento o per chiarezza del codice e manutenibilità?.

    
posta NothingsImpossible 03.05.2014 - 02:34
fonte

3 risposte

1

Non va mai bene soddisfare i goblin delle prestazioni ipotetici a scapito di un numero minore di righe di codice o di una API che esprime più chiaramente la relazione tra le entità.

Quindi, il primo esempio è preferito. Qualsiasi ORM decente dovrebbe essere in grado di caricare la raccolta in modo pigro, e alcuni di quelli più avanzati permetteranno persino di definire una proprietà su un'entità con una funzione di caricamento personalizzata, anch'essa a carico lento. Ciò si prende cura di entrambi i casi d'uso senza interrompere l'incapsulamento della classe Order ed esporre la sua struttura interna dei dati.

    
risposta data 03.05.2014 - 18:14
fonte
1

Dal punto di vista del TDD preferirei pocos con le raccolte rispetto all'utilizzo di metodi LoadSubItems specializzati perché è molto più facile creare un testOrder con un orderitem di prendere in giro un databaseLoadMethod per implementare un test per un servizio di elaborazione ordini.

    
risposta data 03.05.2014 - 17:00
fonte
0

I am used to develop using POCO classes in my projects, that is, domain objects contain absolutely no logic, only data.

Prima di tutto, i tuoi oggetti non dovrebbero essere solo dati. Il comportamento è fondamentale per il tuo dominio e quindi gli oggetti del tuo dominio dovrebbero contenere una logica comportamentale. Se mai dovrebbero contenere tutta la tua logica comportamentale.

Gli oggetti di dominio che sono solo dati sarebbero ciò che Martin Fowler chiama un modello di dominio anemico

POCO significa semplicemente che non si creano oggetti nel modello di dominio con dipendenze a librerie o librerie esterne. Non rendi le tue classi tutti figli di FunkyORMLibrary7 o qualcosa del genere. Gli oggetti dovrebbero essere semplici vecchi oggetti che possono essere eseguiti senza caricare alcun modulo esterno, questo riduce la dipendenza e li rende anche facili da testare in isolamento. Ma ciò non significa nessuna logica in loro, al contrario.

I am wondering which is the best approach when dealing with class relationships - to put a collection inside the class or to request it later.

Dovresti limitare chi ha la responsabilità di inviare messaggi agli oggetti Item Order in base alle responsabilità. Chi è responsabile di garantire l'integrità dell'ordine di chi include tutti gli articoli in un ordine. In entrambi i casi, estraggono gli ordini dall'ordine che li contiene e operano sugli articoli in modo indipendente. Questo, nella maggior parte dei casi, è una cattiva idea.

Pensa ad un esempio del mondo reale. Se lavorassi in un'azienda, permetteresti a chiunque nell'azienda di modificare le informazioni su un documento d'ordine? Immagino di no, si finirebbe con una situazione in cui il custode ha appena trasformato un ordine per 5 iPhone in un ordine di 50 milioni di iPhone.

Alcuni dei quali richiedono una logica di dominio che controlli quali azioni sono o non sono valide per un articolo dell'ordine. Solo l'oggetto che contiene questa logica dovrebbe essere autorizzato a operare sugli articoli dell'ordine.

Ha molto più senso che gli Articoli Ordine siano accessibili solo attraverso l'oggetto Ordine che li contiene, poiché probabilmente è lì che si terrà tutta quella logica. In questo caso nessuno dei tuoi esempi funziona. Il ciclo for che si trova in entrambi gli esempi dovrebbe essere nell'oggetto Order, non al di fuori di esso e nulla dovrebbe essere in grado di scorrere gli elementi dell'ordine diversi dall'oggetto order stesso.

A meno che tu non abbia una ragione molto buona per accedere a un singolo articolo dell'ordine al di fuori dell'ordine che lo contiene, il resto del tuo sistema non dovrebbe essere in grado di accedere all'oggetto dell'ordine al di fuori dell'ordine che lo contiene. Questa è la nozione chiave del principio di incapsulamento in OO e di una radice di aggregazione in DDD.

Di nuovo da Martin Fowler DDD Aggregate

Un aggregato DDD è un cluster di oggetti dominio che possono essere trattati come una singola unità. Un esempio può essere un ordine e i suoi elementi di linea, questi saranno oggetti separati, ma è utile considerare l'ordine (insieme ai suoi elementi pubblicitari) come un singolo aggregato ... Qualsiasi riferimento dall'esterno dell'aggregato dovrebbe solo andare al radice aggregata. La root può quindi garantire l'integrità dell'aggregato nel suo complesso.

    
risposta data 08.05.2014 - 13:00
fonte

Leggi altre domande sui tag