DDD - Aggrega ereditarietà e repository, come progettare correttamente questa situazione?

2

Sto lavorando su un sistema di magazzino legacy. C'è una radice Aggregate, Product che ha il suo corrispondente ProductRepository .

In questo momento ho un nuovo requisito che dice quanto segue:

Some Products are Purchasable and need to keep track of the datetime they have become purchasable.

Quindi, al fine di implementare questo requisito, ho deciso di adottare il seguente approccio che, dal momento che posso vedere una relazione "è-a", ho deciso di creare una nuova classe chiamata PurchasableProduct che eredita Product e aggiunge questo nuovo attributo.

class PurchasableProduct(Product):
    def __init__(product_properties, purchasable_datetime):
        super().__init__(product_properties)
        self.purchasable_datetime = purchasable_datetime

Ciò che mi turba in questo momento sono i repository. ProductRepository , ovviamente, dovrebbe ancora restituire istanze di Products (anche se potrebbero essere PurchasableProducts ), ma ho bisogno di un modo per recuperare e salvare quei Prodotti acquistabili. Aggiungere una PurchasableProductsRepository sembra una soluzione, ma è strano che io possa avere due repository, ProductRepository e PurchasableRepository , che posso usare per salvare istanze di PurchasableProducts .

In un paradigma DDD, quale sarebbe il modo migliore per implementare questa situazione in cui una radice aggregata è una specializzazione di un'altra?

    
posta David Jiménez Martínez 17.10.2017 - 13:19
fonte

2 risposte

2

Il tuo istinto è giusto, sia il Prodotto che il Prodotto Acquistabile dovrebbero essere recuperati dal ProductRepository.

Questo non dovrebbe essere un problema, dal momento che uno eredita dall'altro, ad esempio aggiungiamo una tabella aggiuntiva al database con i campi aggiuntivi PurchasableProduct , a sinistra partecipa all'istruzione select Product e quindi dove non è null invece di istanziare e compilare un nuovo Product , istanziamo un nuovo PurchasableProduct . È ancora possibile restituire un array / elenco di prodotti. quando chiami il metodo Purchase () sovrascritto, ad esempio, PurchasableProduct controllerà la sua data e Product wont.

In sostanza, la sottotitolazione di classe sostituisce semplicemente un'istruzione condizionale nel metodo Purchase e alcuni campi nullable in Product. Il suo codice più ordinato, ma t non dovrebbe modificare il flusso generale dell'applicazione.

Se hai un'esigenza specifica di ottenere solo i prodotti acquistabili, potresti aggiungere un metodo GetProductsWhichArePurchasable() al repository per consentire l'ottimizzazione. Se si restituisce ancora un elenco di Product s o PurchasableProduct s è interessante. Penso che un purista si attenga al prodotto, ma dal momento che stai ottimizzando comunque ...

    
risposta data 17.10.2017 - 13:31
fonte
3

it's kind of weird that I can have two repositories

Abituati.

Per lungo tempo è stato considerato un buon esempio per modellare esplicitamente casi d'uso . Dal punto di vista dell'applicazione, ha un riferimento a un repository che svolge il ruolo di fornire un riferimento a un particolare sapore di radice aggregata.

Quindi potresti avere

interface Product {
    // ...
}

interface ProductRepository {
    Product get(Id id);
}

interface PurchasableProduct {
    // ...
}

interface PurchaseableProductRepository {
    PurchasableProduct get(Id id);
}

Con casi d'uso che necessitano di accedere a prodotti acquistabili collegati al repository PurchaseableProducts.

L'applicazione non ha bisogno di sapere se le implementazioni sottostanti sono uguali.

L'implementazione sottostante può sicuramente diventare complicata; ad esempio, non si desidera perdere l'ora della data acquistabile se un prodotto viene aggiornato utilizzando il repository che non conosce tali informazioni.

Il modo in cui sono arrivato a pensarci: la rappresentazione persistente dell'aggregato è un messaggio , da una versione passata del modello di dominio al presente (e al futuro). Quindi i principi base della compatibilità dei messaggi sono ancora validi: abbiamo bisogno di devi-ignorare e devi- avanti semantica.

In breve, se utilizziamo un ProductRepository per archiviare un prodotto acquistabile, dobbiamo essere sicuri che l'implementazione non sovrascriva le proprietà di cui non sa nulla.

    
risposta data 17.10.2017 - 15:28
fonte

Leggi altre domande sui tag