【发布时间】: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