Design patterns 具有多个存储选项的持久数据树的模式?
我有一个现实世界的问题,我将试图把它抽象成一个说明性的例子 假设我在树中有数据对象,父对象可以访问子对象,子对象可以访问父对象:Design patterns 具有多个存储选项的持久数据树的模式?,design-patterns,data-structures,tree,repository,persistence,Design Patterns,Data Structures,Tree,Repository,Persistence,我有一个现实世界的问题,我将试图把它抽象成一个说明性的例子 假设我在树中有数据对象,父对象可以访问子对象,子对象可以访问父对象: // Interfaces interface IParent<TChild> { List<TChild> Children; } interface IChild<TParent> { TParent Parent; } // Classes class Top : IParent<Middle> {} class
// Interfaces
interface IParent<TChild> { List<TChild> Children; }
interface IChild<TParent> { TParent Parent; }
// Classes
class Top : IParent<Middle> {}
class Middle : IParent<Bottom>, IChild<Top> {}
class Bottom : IChild<Middle> {}
// Usage
var top = new Top();
var middles = top.Children; // List<Middle>
foreach (var middle in middles) {
var bottoms = middle.Children; // List<Bottom>
foreach (var bottom in bottoms) {
var middle = bottom.Parent; // Access the parent
var top = middle.Parent; // Access the grandparent
}
}
通过这种方式,我可以为每个数据存储创建一个映射器,并从我想要的映射器构建对象,然后使用我想要的映射器将其保存回
这里有一个循环引用,但我想这不是问题,因为大多数语言只存储对象的内存引用,所以实际上不会有无限的数据
这方面的问题是,每当我想要构造一个新的Top
、Middle
或Bottom
,它都需要在该对象的父属性或子属性中构建整个对象树,并包含所有数据存储请求和所需的内存使用。在现实生活中,我的树比这里的要大得多,所以这是个问题
对象中的请求
在这种情况下,对象请求其父对象和子对象自己:
class Middle {
private List<Bottom> _children = null; // cache
public List<Bottom> Children {
get {
_children = _children ?? BottomMapper.FetchForMiddle(this);
return _children;
}
set {
BottomMapper.UpdateForMiddle(this, value);
_children = value;
}
}
}
中产阶级{
私有列表_children=null;//缓存
公开儿童名单{
得到{
_children=_children??BottomMapper.fetchFormidle(此);
返回儿童;
}
设置{
UpdateForMiddle(这个值);
_儿童=价值;
}
}
}
我认为这是一个例子。对吗
这个解决方案看起来很简洁——数据只在您需要时从数据存储中被请求,然后如果您想再次请求它,它就会存储在对象中,从而避免进一步的请求
但是,我有两个不同的数据源。有一个数据库,但也有一个web服务,我需要能够从web服务创建一个对象并将其保存回数据库,然后再次从数据库请求它并更新web服务
这也让我感到不安,因为数据对象本身不再对数据源一无所知。我们引入了一个新的依赖项,更不用说循环依赖项了,这使得它更难测试。对象现在屏蔽了它们与数据库的通信
其他解决方案
是否有其他解决方案可以解决多个存储区的问题,但也意味着我不需要每次都构建/请求所有数据?您实际上是在问两个不相关的问题。是的,存储库模式应该导致从项目本身(实体)对存储一无所知的存储中提取项目。因此,您通常拥有实现CRUD的存储库,每当您需要一个实体时,您都可以从那里获得它们。我不明白地图绘制的意义,也不明白你为什么需要中产阶级
第二个问题是如何处理可能不是一次建成的大树。因为您用设计模式标记了它,所以建议树类应该实现,而不是“映射器”,您应该有一个。然后,建设者必须能够分阶段构建东西。这是一个有趣的问题。在依赖注入的世界中,这一点更加复杂
试着考虑一个版本,它不会有仅仅用于位置区分的类,我认为Composite将使之成为可能。我认为Composite只适用于某些类型的树-“当客户端应该忽略对象和单个对象的组成之间的差异时”(来自Wikipedia)。我的树不是这样的。收藏绝对不同于个人。至于“构建器”模式,它说“相同的构建过程可以创建不同的表示”。我想要的是相反的——不同的构造过程(来自不同的数据格式)产生相同的表示。Re:为什么我需要中产阶级——这是说明的一部分。我只是说,我的树中有同时具有父项和子项的项。我建议复合的原因是,您显示的是基于位置逻辑的不同类,因此复合可以消除这些差异。在构建器模式中,您是在反向阅读。请看四人帮中的示例:您正在从两种不同的表示构建一些东西。他们的例子正好说明了这一点。
class Middle {
private List<Bottom> _children = null; // cache
public List<Bottom> Children {
get {
_children = _children ?? BottomMapper.FetchForMiddle(this);
return _children;
}
set {
BottomMapper.UpdateForMiddle(this, value);
_children = value;
}
}
}