Това е толкова прост и често срещан сценарий, че се чудя как успях досега и защо имам проблеми сега.
Имам този обект (част от сглобката на инфраструктурата)
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);
Нищо необичайно тук. Този обект обаче ще бъде изпратен в хранилище, където ще бъде запазен. Обектът Опашка ще поиска от хранилището елементи. Хранилището трябва да създаде отново обекти QueueItem.
Въпреки това, както виждате, свойствата на QueueItem са непроменливи, свойството AddedOn трябва да бъде зададено само веднъж, когато елементът е създаден. Свойството Id ще бъде зададено от обекта Queue (това не е важно).
Въпросът е как трябва да пресъздам QueueItem в хранилището? Мога да имам друг конструктор, който ще изисква всяка стойност за ВСИЧКИ свойства, но не искам този конструктор да е наличен за сборката, която първоначално ще създаде елемента на опашката. Хранилището е част от различна сборка, така че вътрешното няма да работи.
Мислех да осигуря фабричен метод class QueueItem { /* ..останалите дефиниции.. */
public static QueueItem Restore(/* list of params*/){}
}
което поне изчиства намерението, но не знам защо не ми харесва този подход. Бих могъл също да наложа създаването на елемент само от Queue, но това означава да предам Queue като зависимост към repo, което отново не е нещо, което бих искал. Да имаш конкретен фабричен обект за това също изглежда прекалено много.
Основно въпросът ми е: кой е оптималният начин за пресъздаване на обект в хранилището, без излагане на тази конкретна функционалност за създаване на друг потребителски обект.
Актуализация
Важно е да се отбележи, че под хранилище имам предвид самия модел като абстракция, а не обвивка върху ORM. Няма значение как или къде се запазват обектите на домейна. Има значение как може да бъде пресъздадено от хранилището. Друго важно нещо е, че моят модел на домейн е различен от модела на постоянство. Използвам RDBMS, но мисля, че това е просто детайл на изпълнението, който не трябва да има никакво значение, тъй като търся начин, който не зависи от конкретен достъп до съхранение.
Въпреки че това е конкретен сценарий, той може да се приложи основно към всеки обект, който ще бъде възстановен от репото.
Актуализация 2
Добре, не знам как мога да забравя за AutoMapper. Бях с погрешно впечатление, че не може да картографира частни полета/настройка, но може и мисля, че това е най-доброто решение.
Всъщност мога да кажа, че оптималните решения (IMO) са в ред:
- Директно десериализиране, ако е налично.
- Автоматична карта.
- Фабричен метод на самия домейн обект.
Първите две не изискват обектът да прави нещо конкретно, докато третият изисква обектът да предоставя функционалност за този случай (начин за въвеждане на валидни данни за състоянието). Има ясно намерение, но до голяма степен върши работа като картограф.
Отговор Актуализиран
За да си отговоря, в този случай оптималният начин е да се използва фабричен метод. Първоначално избрах Automapper, но открих, че използвам фабричния метод по-често. Automapper може да бъде полезен понякога, но в много случаи не е достатъчен.