这是一个非常简单和常见的场景,我想知道为什么我之前能够处理好它,现在却遇到问题。
我有这个对象(Infrastructure程序集的一部分)
public class Queue {}
public class QueueItem
{
public QueueItem(int blogId,string name,Type command,object data)
{
if (name == null) throw new ArgumentNullException("name");
if (command == null) throw new ArgumentNullException("command");
BlogId = blogId;
CommandType = command;
ParamValue = data;
CommandName = name;
AddedOn = DateTime.UtcNow;
}
public Guid Id { get; internal set; }
public int BlogId { get; private set; }
public string CommandName { get; set; }
public Type CommandType { get; private set; }
public object ParamValue { get; private set; }
public DateTime AddedOn { get; private set; }
public DateTime? ExecutedOn { get; private set; }
public void ExecuteIn(ILifetimeScope ioc)
{
throw new NotImplementedException();
}
}
这将在另一个程序集中创建,方法如下:
var qi = new QueueItem(1,"myname",typeof(MyCommand),null);
这里没有什么不寻常的。但是,这个对象将被发送到一个存储库中进行持久化。 Queue 对象将向存储库请求项目。存储库应该重新创建 QueueItem 对象。
然而,正如您所看到的,QueueItem 属性是不变的,AddedOn 属性只有在创建项目时设置一次。 Id 属性将由 Queue 对象设置(这不重要)。
问题是我应该如何在存储库中重新创建 QueueItem?我可以有另一个构造函数,它需要所有属性的每个值,但我不希望该构造函数对最初创建队列项的程序集可用。存储库是不同程序集的一部分,因此内部无法工作。
我考虑提供一个工厂方法: class QueueItem { /* ..其余定义.. */
public static QueueItem Restore(/* list of params*/){}
}
至少这种方法清楚了意图,但我不知道为什么我不喜欢这种方法。我也可以只通过队列强制执行项的创建,但这意味着将队列作为依赖项传递给存储库,这也不是我想要的。为此专门创建一个工厂对象似乎也过于复杂。
基本上我的问题是:在不向另一个使用者对象公开特定创建功能的情况下,重新创建存储库中的对象的最佳方法是什么。
更新
重要的是要注意,我所说的存储库是指模式本身作为抽象,而不是ORM的包装器。域对象保存在何处或如何保存并不重要。重要的是存储库如何重新创建它们。另一件重要的事情是,我的领域模型与持久性模型是不同的。我确实使用关系数据库管理系统,但我认为这只是一个不应承担任何重要性的实现细节,因为我正在寻找不依赖于特定存储访问的方式。
虽然这是一个具体的场景,但它可以应用于基本上每个将由repo恢复的对象。
更新2
好吧,我不知道我怎么会忘记Automapper。我错误地认为它不能映射私有字段/设置器,但它可以,我认为这是最好的解决方案。
事实上,我可以说最佳解决方案(在我看来)按顺序为:
- 如果可用,直接反序列化。
- Automap。
- 域对象本身的工厂方法。
前两个不需要对象做任何特定的事情,而第三个则需要对象提供该情况的功能(输入有效状态数据的方法)。它具有明确的意图,但它基本上只执行了映射器的工作。
答案已更新
回答自己,在这种情况下,最佳方法是使用工厂方法。最初我选择了Automapper,但我发现自己更经常使用工厂方法。Automapper有时可能很有用,但在许多情况下并不足够。