【问题标题】:Object creation strategy in domain driven design with repositories具有存储库的域驱动设计中的对象创建策略
【发布时间】:2011-12-13 09:55:53
【问题描述】:

我在玩领域驱动开发。我正在使用定义如下的通用存储库实现:(实现为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 上的属性与实体对象上的构造函数匹配。

实施:

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

【问题讨论】:

  • 将 CreateObject() 方法放入存储库是否有特殊原因,即使用通用方法创建对象有什么好处?在 DDD 中,我相信对象创建将是工厂而不是存储库的责任。通常,存储库将具有用于将现有对象添加到存储的 Add 方法。
  • 这是一个很好的观点,如果我将它添加到工厂并希望保持其通用性,但同样的情况也适用。
  • @BasB 你应该考虑停止让一切通用化,如果你需要一些参数,你不能让你的对象创建通用化,不要太严格地应用 DRY。

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


【解决方案1】:

一些建议,我会做如下。

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

【讨论】:

  • 我在 IGuidGeneration 接口中生成 GUID,使用依赖注入解决。
  • 没关系,但是混合基础设施和域,可能并不理想,即使使用依赖注入。
【解决方案2】:

如果您不想实现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; 
    }
}

【讨论】:

  • 听起来像是一个计划,要检查我是否可以创建一个基于此创建对象的 IL 发射器。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-07
  • 1970-01-01
  • 1970-01-01
  • 2014-08-06
  • 1970-01-01
相关资源
最近更新 更多