DDD: Diseño de Fábrica de Modelo de Dominio

7

Estoy tratando de entender cómo y dónde implementar las fábricas de modelos de dominio. He incluido mi agregado Company como una demostración de cómo lo he hecho.

He incluido mis decisiones de diseño al final: agradecería cualquier comentario, sugerencia, crítica sobre esos puntos.

El modelo de 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 fábrica de dominios CompanyFactory :

Esta clase se utiliza para garantizar que las reglas comerciales y las invariantes no se infrinjan al crear nuevas instancias de modelos de dominio. Residiría en la capa de 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);
    }
}

El asignador de entidad CompanyMapper :

Esta clase se usa para mapear entre modelos de dominio enriquecidos y entidades de datos de Entity Framework. Residiría en capas de infraestructura.

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. El constructor Company se declara como internal .
    Motivo: Solo la fábrica debe llamar a este constructor. internal garantiza que ninguna otra capa pueda crear una instancia (las capas están separadas por proyectos VS).

  2. El método CompanyFactory.CreateNew(string name) se usaría al crear una nueva empresa en el sistema.
    Motivo: Como no se habría conservado aún, se necesitará una nueva identidad única que se generará para ello (utilizando el IIdentityFactory ).

  3. El método CompanyFactory.CreateExisting(int id, string name) será utilizado por el CompanyRepository al recuperar elementos de la base de datos.
    Motivo: El modelo ya tendría identidad, por lo tanto, esto debería ser suministrado a la fábrica.

  4. El CompanyMapper.MapFrom(CompanyTable dataEntity) será utilizado por el CompanyRepository cuando recupere datos de la persistencia.
    Motivo: Aquí las entidades de datos de Entity Framework deben asignarse a los modelos de dominio. El CompanyFactory se utilizará para crear el modelo de dominio para garantizar que se cumplan las reglas comerciales.

  5. El CompanyMapper.MapFrom(Company domainEntity) será utilizado por el CompanyRepository al agregar o actualizar modelos a la persistencia.
    Motivo: los modelos de dominio deben asignarse directamente a las propiedades de la entidad de datos para que ese Entity Framework puede reconocer qué cambios hacer en la base de datos.

Gracias

    
pregunta davenewza 03.02.2014 - 11:22

1 respuesta

2

Hay una cosa que no me gusta de tu diseño. Y ese es el hecho de que tendrá 3 clases adicionales para cada raíz agregada (Factory, Mapper, Repository) con código semi-duplicado en forma de lectura y configuración de propiedades en todas partes. Esto será problemático a medida que agregue y elimine propiedades, ya que olvidarse de cambiar un solo método puede causar un error. Y cuanto más compleja es la entidad de dominio, más de este código duplicado es. No quiero ver CompanyFactory.CreateExisting cuando la compañía tiene 10 propiedades y 2 entidades en total.

La segunda cosa de la que podría quejarme es el IdentityFactory . En DDD, la identidad debe estar relacionada con el dominio, en cuyo caso lo establece en un valor calculado. O es transparente, en cuyo caso puede hacer que DB se encargue de ello. Agregar algún tipo de fábrica para la identidad es un exceso de ingeniería de la OMI.

Tampoco me gusta el mapeo. Si bien estoy de acuerdo en que podría no ser posible utilizar EntityFramework directamente, al menos podrías intentarlo. EF está mejorando últimamente con POCO y te sorprenderás de lo poderoso que es. Pero todavía no es NHibernate. Si realmente desea crear modelos separados, intente pensar en usar alguna biblioteca de asignación automática.

Es bueno que esté demoing el diseño en una clase simple, pero intente también demoing o al menos imagine cómo funcionará el diseño con docenas de agregados que tienen muchas propiedades y entidades. Además, escribe un código que usará este diseño. Podría darse cuenta de que, si bien el diseño puede verse bien desde el interior, es incómodo de usar desde el exterior. Además, nadie aquí le dirá si el diseño es apropiado para su equipo y su dominio.

    
respondido por el Euphoric 03.02.2014 - 11:56

Lea otras preguntas en las etiquetas