Стратегия создания объектов в доменном дизайне с репозиториями - PullRequest
4 голосов
/ 13 декабря 2011

Я играю с разработкой, управляемой доменом.Я использую стандартную реализацию репозитория, которая определяется следующим образом: (это реализовано как Repository<T>)

   public interface IRepository<T> where T : class, IEventSource, new()
    {
        T FindByKey(Guid key);
        IEnumerable<T> FindByQuery(Predicate<T> filter);
        IEnumerable<T> GetAll();
        T CreateObject();
    }

Допустим, у меня есть класс Order, который нельзя создать без параметра Customer.Я использую CreateObject, чтобы установить ключ сущности с последовательным генератором Guid.

Какое решение минимизирует время разработки и связывание?

  • В настоящее время у меня есть конструктор без параметрови я вызываю некоторый метод Initialize (Customer).
  • Я мог бы создать ICustomerRepository, но это означало бы, что для каждой сущности требуется дополнительное время разработки.
  • Я также могу изменить CreateObject навозьмите params object[] args, но это не типобезопасно во время компиляции.
  • Я мог бы удалить CreateObject и использовать конструкторы для создания объекта, но это означает, что мне нужно иметь доступ к алгоритму генерации Guid везде, где я создаю экземпляробъект, увеличивающий связь.
  • В базовом классе для сущности я мог бы установить ключ в конструкторе, уменьшив связь, но требуя некоторой статической ссылки на алгоритм.

Обновление

Я реализовал стратегию после ответа sll.Новая подпись для хранилища теперь:

public interface IRepository<T> where T : class, IEventSource
{
    T FindByKey(Guid key);
    IEnumerable<T> FindByQuery(Func<T, bool> predicate);
    IEnumerable<T> GetAll();
    T CreateObject();
    T CreateObject(IConstructorParameters parameters);
}

Без параметров CreateObject создает экземпляр, пытаясь вызвать конструктор без параметров (используя IL Emit для производительности).

Второй CreateObject пытается создать метод, вызывающий конструктор, в котором свойства IConstructorParameters соответствуют конструктору объекта Entity.

Реализация:

private Dictionary<Type, Func<IConstructorParameters, T>> _constructionMethods 
    = new Dictionary<Type, Func<IConstructorParameters, T>>();
public T CreateObject(IConstructorParameters args)
{
    T newObject;
    if (args == null)
    {
        args = ConstructorParameters.Empty;
    }
        Type paramType = args.GetType();
        Func<IConstructorParameters, T> constructor;

        if (!_constructionMethods.TryGetValue(paramType, out constructor))
        {
            //Emit IL to create a Func<IConstructorParameters,T>
            constructor = CreateConstructor(paramType);
            _constructionMethods.Add(paramType, constructor);
        }

        newObject = constructor(args);

    newObject.Key = _guidCreator.Generate();
    return newObject;
}

Ответы [ 2 ]

2 голосов
/ 13 декабря 2011

Некоторые пункты в качестве предложения, я бы поступил следующим образом.

  • Сохраняйте универсальный IRepository, а также создавайте конкретные интерфейсы, содержащие контракт только с тем, что имеет отношение к сущности, ICustomerRepository в качестве вашего примера.
  • Удалите генерацию guid для класса обслуживания, поскольку эта задача наиболее актуальна для инфраструктуры, а не для домена.
1 голос
/ 13 декабря 2011

Если вы не хотите реализовывать IOrderRepository - вы можете абстрагировать параметры метода CreateObject() с помощью интерфейса, такого как IConstructionParameters, а затем для каждого объекта реализовать конкретные параметры, такие как OrderConstructionParameters.

Этот подход также известен как Параметр объекта шаблон проектирования, обоснование которого - больше отделен проект системы.

public interface IRepository<T> 
{
   T CreateObject(IConstructionParameters parameters);     
} 

public sealed class OrderConstructionParameters : IConstructionParameters
{
    public Customer Customer
    { 
       get; 
       private set; 
    }
}
...