具有存储库的域驱动设计中的对象创建策略

时间:2011-12-13 09:55:53

标签: c# design-patterns domain-driven-design

我正在玩Domain Driven Development。我使用的通用存储库实现定义如下:(这实现为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生成器设置实体的Key。

什么是最小化开发时间和耦合的解决方案?

  • 目前我有一个无参数构造函数,我正在调用一些 初始化(客户)方法。
  • 我可以创建一个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 个答案:

答案 0 :(得分:2)

作为建议的一些观点,我会做如下。

  • 保持IRepository的通用性,并且还创建包含合同的特定接口,仅包含与实体相关的内容,ICustomerRepository作为示例。
  • 将guid生成删除到服务类,因为此任务与基础结构最相关,而非域。

答案 1 :(得分:1)

如果您不想要实现IOrderRepository - 您可以通过CreateObject()之类的接口抽象IConstructionParameters方法参数,然后为每个实体实现具体参数,如OrderConstructionParameters

这种方法也称为Parameter Object设计模式,其设计原理 - 更多decoupled系统设计。

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

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