我试图想出一个命名约定来准确地传达我正在设计的课程中发生的事情。在第二点上,我试图在两个几乎等效的用户 API 之间做出决定。
情况如下:
我正在构建一个科学应用程序,其中一个中央数据结构具有三个阶段:1)积累、2)分析和 3)查询执行。
在我的例子中,它是一种空间建模结构,在内部使用 KDTree 来划分 3 维空间中的点集合。每个点都描述了周围环境的一个或多个属性,对测量本身具有一定的置信度。
在向集合添加(可能大量)测量后,对象的所有者将查询它以获取适用字段内某处新数据点处的插值测量。
API 看起来像这样(代码是用 Java 编写的,但这并不重要;为清楚起见,代码分为三个部分):
// SECTION 1:
// Create the aggregation object, and get the zillion objects to insert...
ContinuousScalarField field = new ContinuousScalarField();
Collection<Measurement> measurements = getMeasurementsFromSomewhere();
// SECTION 2:
// Add all of the zillion objects to the aggregation object...
// Each measurement contains its xyz location, the quantity being measured,
// and a numeric value for the measurement. For example, something like
// "68 degrees F, plus or minus 0.5, at point 1.23, 2.34, 3.45"
foreach (Measurement m : measurements) {
field.add(m);
}
// SECTION 3:
// Now the user wants to ask the model questions about the interpolated
// state of the model. For example, "what's the interpolated temperature
// at point (3, 4, 5)
Point3d p = new Point3d(3, 4, 5);
Measurement result = field.interpolateAt(p);
对于我的特定问题域,可以在第 2 节期间执行少量增量工作(将点划分为平衡的 KDTree)。
在第 3 节期间可能会发生少量工作(执行一些线性插值)。
但是在第 2 节和第 3 节之间必须执行大量工作(构建核密度估计器并执行快速高斯变换,使用泰勒级数和 Hermite 函数,但这完全是题外话) 。
有时在过去,我只是使用惰性求值来构造数据结构(在这种情况下,它会在第一次调用“interpolateAt”方法时),但是如果用户调用“field.add ()" 方法,我必须完全丢弃那些数据结构并从头开始。
在其他项目中,我要求用户显式调用“object.flip()”方法,从“附加模式”切换到“查询模式”。这样的设计的好处是用户可以更好地控制核心计算开始的确切时刻。但是对于 API 使用者来说,跟踪对象的当前模式可能会很麻烦。此外,在标准用例中,调用者在开始发出查询后永远不会向集合添加另一个值;数据聚合几乎总是完全在查询准备之前。
你们是如何设计这样的数据结构的?
您是否更喜欢让对象懒惰地执行其繁重的分析,当新数据进入集合时丢弃中间数据结构?或者您是否需要程序员显式地将数据结构从附加模式转换为查询模式?
你知道像这样的对象有什么命名约定吗?有没有我没有想到的模式?
编辑:
我在示例中使用的名为“ContinuousScalarField”的类似乎有些困惑和好奇。
通过阅读这些维基百科页面,您可以很好地了解我在说什么:
假设您想创建一个地形图(这不是我的确切问题,但在概念上非常相似)。因此,您在一平方英里的区域内进行了一千次高度测量,但您的测量设备在高度上的误差范围为正负 10 米。
一旦你收集了所有的数据点,你就可以将它们输入一个模型,该模型不仅可以插值,还可以考虑每次测量的误差。
要绘制地形图,您需要在模型中查询要绘制像素的每个点的高程。
至于单个类是否应该同时负责追加和处理查询的问题,我不是 100% 肯定,但我认为是的。
这是一个类似的示例:HashMap 和 TreeMap 类允许添加和查询对象。没有用于添加和查询的单独接口。
这两个类也与我的示例相似,因为必须持续维护内部数据结构以支持查询机制。HashMap 类必须定期分配新内存,重新散列所有对象,并将对象从旧内存移动到新内存。TreeMap 必须使用红黑树数据结构持续保持树平衡。
唯一的区别是,如果我的班级一旦知道数据集已关闭,它就可以执行所有计算,那么它将表现最佳。