DDD: modello di fabbrica modello di dominio

8

Sto cercando di capire come e dove implementare le fabbriche dei modelli di dominio. Ho incluso il mio Company aggregato come demo di come l'ho fatto.

Ho incluso le mie decisioni sul design alla fine - apprezzerei qualsiasi commento, suggerimento, critica su quei punti.

Il modello di dominio Company :

public class Company : DomainEntity, IAggregateRoot
{
    private string name;
    public string Name
    {
        get
        {
            return name;
        }
        private set
        {
            if (String.IsNullOrWhiteSpace(value))
            {
                throw new ArgumentOutOfRangeException("Company name cannot be an empty value");
            }

            name = value;
        }
    }

    internal Company(int id, string name)
    {
        Name = name;
    }
}

La factory di dominio CompanyFactory :

Questa classe viene utilizzata per garantire che le regole aziendali e gli invarianti non vengano violati durante la creazione di nuove istanze di modelli di dominio. Si troverebbe nel livello del dominio.

public class CompanyFactory
{
    protected IIdentityFactory<int> IdentityFactory { get; set; }

    public CompanyFactory(IIdentityFactory<int> identityFactory)
    {
        IdentityFactory = identityFactory;
    }

    public Company CreateNew(string name)
    {
        var id = IdentityFactory.GenerateIdentity();

        return new Company(id, name);
    }

    public Company CreateExisting(int id, string name)
    {
        return new Company(id, name);
    }
}

Il CompanyMapper entity mapper:

Questa classe viene utilizzata per eseguire il mapping tra i modelli di dominio ricco e le entità di dati Entity Framework. Viverebbe in strati infrastrutturali.

public class CompanyMapper : IEntityMapper<Company, CompanyTable>
{
    private CompanyFactory factory;

    public CompanyMapper(CompanyFactory companyFactory)
    {
        factory = companyFactory;
    }

    public Company MapFrom(CompanyTable dataEntity)
    {
        return DomainEntityFactory.CreateExisting(dataEntity.Id, dataEntity.Name);
    }

    public CompanyTable MapFrom(Company domainEntity)
    {
        return new CompanyTable()
        {
            Id = domainEntity.Id,
            Name = domainEntity.Name
        };
    }
}
  1. Il costruttore Company è dichiarato come internal .
    Motivo: solo la factory dovrebbe chiamare questo costruttore. internal garantisce che nessun altro layer possa istanziarlo (i livelli sono separati dai progetti VS).

  2. Il metodo CompanyFactory.CreateNew(string name) verrebbe utilizzato durante la creazione di una nuova società nel sistema.
    Motivo: Poiché non sarebbe stato ancora persistuto, sarà necessaria una nuova identità univoca da generare per questo (utilizzando IIdentityFactory ).

  3. Il metodo CompanyFactory.CreateExisting(int id, string name) verrà utilizzato da CompanyRepository quando si recuperano gli elementi dal database.
    Motivo: il modello avrebbe già un'identità, quindi sarebbe necessario essere fornito in fabbrica.

  4. Il CompanyMapper.MapFrom(CompanyTable dataEntity) verrà utilizzato da CompanyRepository durante il recupero dei dati dalla persistenza.
    Motivo: Qui le entità dei dati Entity Framework devono essere mappate in modelli di dominio. Il CompanyFactory verrà utilizzato per creare il modello di dominio per garantire che le regole aziendali siano soddisfatte.

  5. Il CompanyMapper.MapFrom(Company domainEntity) verrà utilizzato da CompanyRepository quando si aggiungono o si aggiornano i modelli alla persistenza.
    Motivo: i modelli di dominio devono essere mappati direttamente sulle proprietà dell'entità dati, quindi quel Entity Framework può riconoscere quali modifiche apportare al database.

Grazie

    
posta davenewza 03.02.2014 - 11:22
fonte

1 risposta

2

C'è una cosa che non mi piace del tuo design. E questo significa che avrete 3 classi aggiuntive per ogni radice aggregata (Factory, Mapper, Repository) con codice semi-duplicato in forma di lettura e impostazione delle proprietà ovunque. Ciò sarà problematico man mano che aggiungi e rimuovi le proprietà, perché dimenticarti di cambiare un singolo metodo potrebbe causare un errore. E più l'entità del dominio è complessa, più questo è il codice duplicato. Non voglio vedere CompanyFactory.CreateExisting quando la società ha 10 proprietà e 2 entità in aggregato.

La seconda cosa di cui potrei lamentarmi è il IdentityFactory . In DDD, l'identità dovrebbe essere correlata al dominio, nel qual caso lo si imposta su un valore calcolato. O è trasparente, nel qual caso puoi fare in modo che DB si occupi di esso. L'aggiunta di una sorta di fabbrica per l'identità è l'overenginering IMO.

Inoltre non mi piace la mappatura. Mentre sono d'accordo potrebbe non essere possibile usare EntityFramework direttamente, almeno si potrebbe provare. EF sta migliorando con POCO ultimamente e potresti essere sorpreso di quanto sia potente. Ma non è ancora in NHibernate. Se vuoi davvero creare modelli separati, prova a pensare di utilizzare una libreria di mappatura automatica.

È bello che tu stia dimostrando il design su una semplice classe, ma prova anche a fare demo o almeno immaginando come il progetto funzionerà con dozzine di aggregati che hanno molte proprietà ed entità. Inoltre, scrivi un codice che utilizzerà questo design. Potresti rendertene conto che mentre il design potrebbe sembrare bello dall'interno, è ingombrante da usare dall'esterno. Inoltre, nessuno qui ti dirà se il design è appropriato per la tua squadra e il tuo dominio.

    
risposta data 03.02.2014 - 11:56
fonte