DDD - Управление связью между доменом и хранилищем
У меня очень простой вопрос: как сохранить личные данные моего класса в хранилище для сохранения?
Независимо от принятого нами архитектурного стиля, все согласны с тем, что бизнес-объекты не должны знать, "как" спасти себя, то есть они не должны реализовывать базу данных или другие детали персистентности. Однако мне кажется, что бизнес-объекты - это единственные, кто знает, "что" им нужно сохранить. Репозиторий знает, как извлечь из базы данных, но если он хочет знать, как перевести бизнес-объект в термины базы данных, то он должен знать, что переводить.
Учтите, что я могу использовать базу данных, но я не размечаю свои классы аннотациями гибернации, потому что я мог бы так же часто сохранять их в простой текстовый файл.
Предполагая, что мои классы здесь на самом деле названы в честь конкретных бизнес-объектов, что было бы неправильно делать что-то вроде
interface Exporter
{
public void Export(String id, String value1, String value2);
}
interface Repository
{
public Entity FindById(String id);
}
class Entity
{
private String id;
private String value1;
private String value2;
private String derivedvalue;
public Entity() {}
public Entity(String id, String value1, String value2)
{
this.id = id;
this.value1 = value1;
this.value2 = value2;
this.derivedvalue = /* derived from id, value1, and value2 */;
}
public void DoBusiness()
{
// ...
}
public void Export(Exporter exporter)
{
Exporter.Export(this.id, this.value1, this.value2);
}
}
и используя его как
FlatFileRepositoryAndExporter flatfile = new FlatFileRepositoryAndExporter(...);
Entity entity = flatfile.FindById(...);
// Do business logic
entity.DoBusiness();
entity.Export(flatfile);
Я понимаю, что существуют рамки, которые могут мне помочь, но в конечном итоге все они полагаются на своего рода отражение. Я хочу знать, не задумываясь, как я могу статически составлять свои объекты, чтобы представить их данные, сохраняя при этом инкапсуляцию. Единственный ответ, который я могу придумать - это шаблон посетителей.
2 ответа
Я склонен согласиться с @MikeSW в том, что сделать внешние инструменты персистентности способными собирать состояние объекта домена с помощью незначительных корректировок области (или отражения, как это делают ORM), часто проще, чем позволить самому объекту домена полностью контролировать то, что сохраняется.
Есть третий способ, который заключается в том, чтобы заставить объект испускать события, описывающие то, что произошло, а не раскрывать его состояние - это Event Sourcing. Тогда тот, кто захочет, может слушать их и сохранять изменения в любой форме, которую они хотят получить.
Не усложняй свою жизнь слишком сильно. То, что вы пытаетесь сделать, - это, по сути, сувенир, который работает, но имеет высокие (как при очень скучных) затраты на обслуживание. Я обычно json сериализую вещи независимо от того, где я их храню, и я настроил json.net для сериализации защищенных свойств. В общем, у меня есть защищенные свойства или просто защищенные сеттеры, и это работает довольно хорошо.
Хотя это не пуристическое решение, компромисс очень низок, внутренности объекта не открыты для его пользователя. И вы можете иметь такие вещи, как
private List<string>_data=new List<string>();
public IEnumerable<string> Data
{
get { return _data;}
protected set { _data=value.ToList(); }
}
Этот подход достаточно прост, очень удобен в обслуживании и настойчив в использовании.
Кстати, экспортер, учитывая его цель, должен иметь дело только с публичными членами, и объект не должен знать об этом.