DDD - 管理域和存储库之间的耦合
DDD - Manage Coupling between Domain and Repository
我的问题很简单:如何将我的class的私有数据保存到存储库中?
无论我们采用何种架构风格,每个人都同意业务对象不应该知道 "how" 来保存自己 - 即它们不应该实现数据库或其他持久性细节。但是,在我看来,业务对象是唯一知道 "what" 他们需要保存的对象。存储库知道如何从数据库中获取数据,但如果要知道如何将业务对象转换为数据库术语,那么它必须知道要翻译什么。
考虑到我可能会使用数据库,但我不会用休眠注释标记我的 classes,因为我可能经常保存到平面文本文件。
假设我这里的 classes 实际上是以特定的业务实体命名的,那么这样做会有什么问题
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);
我知道有一些框架可以帮助我,但归根结底,它们都依赖于某种反射。我想知道,不经思考,我如何静态组合我的对象以在保持封装的同时公开它们的数据。我能想到的唯一答案就是这个访问者模式。
不要让你的生活太复杂。您要做的基本上是一个纪念品,它可以工作,但维护成本很高(非常无聊)。我通常 json 序列化东西,不管我实际存储它们在哪里,我已经配置 json.net 序列化受保护的属性。所以基本上,我有受保护的属性或只是受保护的 setter,而且效果很好。
虽然不是纯粹的解决方案,但妥协程度非常低,对象的内部结构不会暴露给用户。你可以拥有像
这样的东西
private List<string>_data=new List<string>();
public IEnumerable<string> Data
{
get { return _data;}
protected set { _data=value.ToList(); }
}
这种方法非常简单,非常易于维护并且与持久性工具无关。
顺便说一句,出口商,考虑到它的目的,应该只处理 public 成员和对象不应该知道它。
我倾向于同意@MikeSW 的观点,即在较小的范围调整(或像 ORM 所做的反射)的帮助下,使外部持久性工具能够收集域对象状态通常比让域对象本身完全控制更简单什么是持久的。
还有第三种方法,即让实体发出事件来描述发生的事情,而不是公开其状态——这就是事件溯源。然后任何想要的人都可以听取这些意见并以他们想要的任何形式坚持改变。
我的问题很简单:如何将我的class的私有数据保存到存储库中?
无论我们采用何种架构风格,每个人都同意业务对象不应该知道 "how" 来保存自己 - 即它们不应该实现数据库或其他持久性细节。但是,在我看来,业务对象是唯一知道 "what" 他们需要保存的对象。存储库知道如何从数据库中获取数据,但如果要知道如何将业务对象转换为数据库术语,那么它必须知道要翻译什么。
考虑到我可能会使用数据库,但我不会用休眠注释标记我的 classes,因为我可能经常保存到平面文本文件。
假设我这里的 classes 实际上是以特定的业务实体命名的,那么这样做会有什么问题
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);
我知道有一些框架可以帮助我,但归根结底,它们都依赖于某种反射。我想知道,不经思考,我如何静态组合我的对象以在保持封装的同时公开它们的数据。我能想到的唯一答案就是这个访问者模式。
不要让你的生活太复杂。您要做的基本上是一个纪念品,它可以工作,但维护成本很高(非常无聊)。我通常 json 序列化东西,不管我实际存储它们在哪里,我已经配置 json.net 序列化受保护的属性。所以基本上,我有受保护的属性或只是受保护的 setter,而且效果很好。
虽然不是纯粹的解决方案,但妥协程度非常低,对象的内部结构不会暴露给用户。你可以拥有像
这样的东西 private List<string>_data=new List<string>();
public IEnumerable<string> Data
{
get { return _data;}
protected set { _data=value.ToList(); }
}
这种方法非常简单,非常易于维护并且与持久性工具无关。
顺便说一句,出口商,考虑到它的目的,应该只处理 public 成员和对象不应该知道它。
我倾向于同意@MikeSW 的观点,即在较小的范围调整(或像 ORM 所做的反射)的帮助下,使外部持久性工具能够收集域对象状态通常比让域对象本身完全控制更简单什么是持久的。
还有第三种方法,即让实体发出事件来描述发生的事情,而不是公开其状态——这就是事件溯源。然后任何想要的人都可以听取这些意见并以他们想要的任何形式坚持改变。