我正在玩域驱动开发。我使用的定义如下通用仓库实现:(这是实现为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;
}
是否有将CreateObject()方法放入存储库的特殊原因,即使用通用方法创建对象有什么好处?在DDD中,我认为创建对象将是工厂而不是仓库的责任。通常情况下,存储库将具有用于将现有对象添加到商店的Add方法。 – David
这是一个很好的观点,如果我将其添加到工厂并希望保持其通用性,则同样的情况适用。 – Bas
@BasB你应该考虑停止使所有东西都是通用的,如果你需要一些参数,你不能使你的对象创建为通用的,不要太严格地应用DRY。 –