我正在玩域驅動開發。我使用的定義如下通用倉庫實現:(這是實現爲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。 –