重构大型数据对象
重构大型“仅状态”对象的一些常见策略是什么?
我正在开发一个特定的软实时决策支持系统,该系统对国家空域进行在线建模/模拟。该软件消耗许多实时数据馈送,并每分钟对空域中大量实体的“状态”进行一次估计。问题会整齐地分解,直到我们达到当前最低级别的实体。
我们的数学模型估计/预测超过50个参数,每个实体的过去和未来几个小时的时间线,大约每分钟一次。目前,这些记录被编码为具有大量字段的单个Java类(有些被折叠成一个)。我们的模型正在不断发展,字段之间的依赖关系尚未一成不变,因此每个实例都在一个复杂的模型中徘徊,并在此过程中累积设置。ArrayList
目前,我们有类似下面的内容,它使用生成器模式方法来构建记录的内容,并强制执行已知的依赖项(作为在模式发展时对程序员错误的检查)。估计完成后,我们使用类型方法将以下内容转换为不可变形式。.build()
final class OneMinuteEstimate {
enum EstimateState { INFANT, HEADER, INDEPENDENT, ... };
EstimateState state = EstimateState.INFANT;
// "header" stuff
DateTime estimatedAtTime = null;
DateTime stamp = null;
EntityId id = null;
// independent fields
int status1 = -1;
...
// dependent/complex fields...
... goes on for 40+ more fields...
void setHeaderFields(...)
{
if (!EstimateState.INFANT.equals(state)) {
throw new IllegalStateException("Must be in INFANT state to set header");
}
...
}
}
一旦大量这些估计完成,它们就会被组装成分析聚合模式/趋势的时间线。我们已经考虑过使用嵌入式数据库,但一直在努力解决性能问题。我们宁愿在数据建模方面对此进行整理,然后逐步将部分软实时代码移动到嵌入式数据存储中。
完成“时间敏感”部分后,产品将被刷新到平面文件和数据库中。
问题:
- 这是一个巨大的类,有太多的领域。
- 类中编码的行为很少;它主要是数据字段的持有者。
- 维护该方法非常麻烦。
build()
- 仅仅为了确保大量依赖建模组件正确填充数据对象而手动维护“状态机”抽象感觉很笨拙,但随着模型的发展,它为我们节省了很多挫折感。
- 存在大量重复,特别是当上述记录聚合成非常相似的“汇总”时,这些汇总相当于时间序列中上述结构的滚动总和/平均值或其他统计乘积。
- 虽然有些领域可以聚集在一起,但它们在逻辑上都是彼此的“对等体”,我们尝试过的任何细分都会导致行为/逻辑人为地分裂,并且需要在间接性中达到两个层次。
开箱即用的想法很有趣,但这是我们需要逐步发展的东西。在其他人说出来之前,我会注意到,如果有人认为我们的数学模型不够清晰,如果该模型的数据表示很难掌握。公平点,我们正在努力,但我认为这是研发环境的副作用,有很多贡献者,还有很多并发的假设在起作用。
(不是说这很重要,但这是在Java中实现的。我们使用 HSQLDB 或 Postgres 作为输出产品。我们不使用任何持久性框架,部分原因是缺乏熟悉,部分原因是我们仅使用数据库和手动编码的存储例程就有足够的性能问题......我们对转向额外的抽象持怀疑态度。