这是一个如此简单而常见的场景,我想知道到目前为止我是如何做到的以及为什么现在遇到问题。
我有这个对象(基础设施程序集的一部分)
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属性将由队列对象设置(这并不重要)。
问题是我应该如何在存储库中重新创建 QueueItem?我可以有另一个构造函数,它需要所有属性的每个值,但我不希望该构造函数可用于最初创建队列项的程序集。该存储库是不同程序集的一部分,因此内部无法工作。
我考虑过提供一个工厂方法
队列项目类
{
/* ..其余定义.. */
public static QueueItem Restore(/* list of params*/){}
}
这至少明确了意图,但我不知道为什么我不喜欢这种方法。我还可以仅通过 Queue 强制创建项目,但这意味着将 Queue 作为对存储库的依赖项传递,这又不是我想要的。为此拥有一个特定的工厂对象似乎也有点矫枉过正。
基本上我的问题是:在存储库中重新创建对象的最佳方法是什么,不暴露特定的创建功能到另一个消费者对象.
Update
值得注意的是,我所说的存储库是指模式本身作为一种抽象,而不是 ORM 的包装器。域对象的持久化方式和位置并不重要。存储库如何重新创建很重要。另一件重要的事情是我的领域模型 是不同的来自持久化模型。我确实使用 RDBMS,但我认为这只是一个实现细节,不应该具有任何重要性,因为我正在寻找不依赖于特定存储访问的方法。
虽然这是一个特定的场景,但它基本上可以应用于存储库将恢复的每个对象。
Update2
好吧,我不知道我怎么能忘记 AutoMapper。我的错误印象是它无法映射私有字段/设置器,但它可以,而且我认为这是最好的解决方案。
事实上,我可以说最佳解决方案(IMO)是有序的:
- 直接反序列化(如果可用)。
- Automap.
- 域对象本身的工厂方法。
前两个不需要对象做任何特别的事情,而第三个需要对象提供针对这种情况的功能(一种输入有效状态数据的方法)。它有明确的意图,但它几乎完成了映射工作。
Answer Updated
为了回答自己,在这种情况下,最佳方法是使用工厂方法。最初我选择了 Automapper,但我发现自己更频繁地使用工厂方法。自动映射器有时很有用,但在很多情况下它还不够。