Decidere tra un servizio di dominio e un metodo di entità

1

Sto cercando di decidere se utilizzare un servizio di dominio o un metodo di entità per una funzione. Si prega di consultare il codice qui sotto:

public class Customer
{
    private readonly Guid _id;
        private readonly decimal _expenditure;
        private readonly IList<IProduct> _eligibleProducts = new List<IProduct>();
        public IEnumerable<IProduct> EligibleProducts
        {
            get { foreach (var product in _eligibleProducts) yield return product; }
        }

    public void AddProduct(IProduct eligibleProduct)
        {
            _eligibleProducts.Add(eligibleProduct);
        }
}

Il cliente aggiunge prodotti idonei alla raccolta _eligibleProducts tramite il metodo AddProduct.

Per determinare quali sono i prodotti idonei; Credo che ci siano due opzioni:

Opzione 1 - Servizio dominio

public class OfferCalculator : IOfferCalculator
{

        public IEnumerable<IProduct> CalculateEligibility(Customer customer, IList<IProduct> products)
        {
            return products.Where(x => x.IsEligible(customer));
        }
}

In questo caso il servizio applicativo otterrà i prodotti idonei dal Calcolatore dell'offerta e quindi chiamerà Cliente.Aggiungi per aggiungere singolarmente le offerte.

Se in futuro avessi voluto aggiungere altre offerte specifiche, avrei potuto farlo (credo):

BlackFridayOfferCalculator
ChristmasOfferCalculator
EasterOfferCalculator

Dovrei aggiungere un'interfaccia su un servizio di dominio chiamato IOfferCalculator per questo.

Opzione 2 - Metodo entità

Vedi il codice qui sotto, che viene aggiunto alla classe Cliente (classe cliente mostrata sopra):

public IEnumerable<IProduct> DetermineEligibility(IList<IProduct> availableProducts)
{
    return availableProducts.Where(x => x.IsEligible(this));
}

Se in futuro avessi voluto aggiungere altre offerte specifiche, avrei potuto farlo (credo):

BlackFridayCustomer
ChristmasCustomer
EasterCustomer

Dovrei aggiungere un'interfaccia su un'entità chiamata ICustomer per questo.

Sto cercando di usare il principio del minimo stupore.

    
posta w0051977 06.04.2018 - 09:05
fonte

1 risposta

2

Un oracolo da considerare è che, mentre DDD sostiene una netta separazione tra l'applicazione e il modello di dominio, non stravolge le "migliori pratiche" per scrivere codice orientato agli oggetti (dove l'orientato agli oggetti è usato nel C ++ / Senso di Java / C #).

In altre parole, la linea guida Tell, Do not Ask vale ancora.

Quindi questo modello:

In this case the application service will get the eligible products from the Offer Calculator and then call Customer.Add to add the offers individually.

non riesce a seguire le linee guida.

Osserva che stai prendendo ciò che è logica aziendale (capendo quali offerte sono appropriate per un cliente) e implementandolo in un servizio applicazione . La logica aziendale appartiene al modello di dominio.

Poiché Customer._eligibleProducts è i dati che cambiano in questo caso d'uso, dovresti pensare che stai invocando un metodo su Customer aggregato e passando ad esso i dati di cui ha bisogno o la capacità di accedi ai dati di cui ha bisogno .

class Customer {
    // ...

    // note: the lousy name here is a code smell
    // TODO: consult with the domain experts to get a clearer
    // understanding of the language for this use case.

    public void updateProducts(IList<IProduct> availableProducts) {
        this._eligibleProducts.addRange(
            availableProducts.Where(x => x.IsEligible(this));
        );    
    }
}

C'è un ulteriore problema da considerare, ovvero che la tua API IProduct.IsEligible richiede troppa energia; non c'è motivo, ad esempio, che IsEligible possa essere in grado di chiamare AddProduct . Quello che dovresti passare è l'accesso a una copia immutabile dello stato attuale del cliente o un'interfaccia di sola lettura.

    public void updateProducts(IList<IProduct> availableProducts) {
        this._eligibleProducts.addRange(
            availableProducts.Where(x => x.IsEligible(this.currentState()));
        );    
    }
    
risposta data 06.04.2018 - 14:49
fonte

Leggi altre domande sui tag