2011-12-13 50 views
4

我正在玩域驱动开发。我使用的定义如下通用仓库实现:(这是实现为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类,即不能没有客户参数做成。我使用CreateObject来设置实体的Key和一个连续的Guid生成器。

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

  • 目前,我有一个参数的构造函数,和我打电话一些 初始化(客户)方法。
  • 我可以创建一个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:发射性能)创建一个实例。

第二CreateObject尝试创建调用构造,其中上IConstructorParameters属性实体对象上的构造相匹配的方法。

实现:

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; 
} 
+0

是否有将CreateObject()方法放入存储库的特殊原因,即使用通用方法创建对象有什么好处?在DDD中,我认为创建对象将是工厂而不是仓库的责任。通常情况下,存储库将具有用于将现有对象添加到商店的Add方法。 – David

+0

这是一个很好的观点,如果我将其添加到工厂并希望保持其通用性,则同样的情况适用。 – Bas

+0

@BasB你应该考虑停止使所有东西都是通用的,如果你需要一些参数,你不能使你的对象创建为通用的,不要太严格地应用DRY。 –

回答

1

如果您不希望实现IOrderRepository - 你可以像IConstructionParameters接口抽象CreateObject()方法参数,然后为每个实体实现诸如OrderConstructionParameters具体参数。

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

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

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

听起来像一个计划,将检查是否可以创建一个IL发射器,基于此创建对象。 – Bas

2

的几点建议作为,我会做如下。

  • 保持IRepository通用的,也只有什么是相关的实体,ICustomerRepository作为例子创建一个包含合同特定的接口。
  • 将guid生成移除到服务类,因为此任务与基础结构最为相关,而不是域。
+0

我在接口IGuidGeneration中使用依赖注入来解析GUID。 – Bas

+0

没关系,但是混合基础设施和域,可能不是那么理想,即使是依赖注入。 – wnascimento