TL; DR,我正在寻求有关如何组织数百行静态函数的思想,这些函数将取代相互依赖的lazy val x = { a long block }
评估。
我正在使用事件源模型重构一些旧的Scala代码,以使我们的团队更容易理解。我在下面草拟了一个总体计划,但对是否存在更好的模式感兴趣。我目前有一个主要的聚合类,具有许多相互依赖的lazy val = { ... }
属性:
trait Aggregate extends AllTheNecessaryStateWeWillNowImplement {
// define some minimal dependency up front
def storedEvents: Seq[StoredEvent]
lazy val activeEvents: Seq[Event] =
storedEvents.filterNot(e => e.isUndone || e.isIgnored).map(_.event)
lazy val isFoo: Boolean = {
activeEvents.foldLeft(false) {
case (false, FooEvent) => true
case (true, BarEvent) => false
case (prev, _) => prev
}
}
// ... and many more
}
case class DefaultAggregate(storedEvents: Seq[StoredEvent]) extends Aggregate
case class AnotherAggregate ...
因为此基本集合特征已混入其他几个(有时是嵌套的)集合中:
我们研究过的一种简化方法是简单地移动 将所有这些逻辑转换为单独的静态方法:
trait Formulae {
def activeEvents(storedEvents: Seq[StoredEvent]): Seq[Event] =
storedEvents.filterNot(e => e.isUndone || e.isIgnored)
.map(_.event)
def isFoo(activeEvents: Seq[Event]): Boolean = {
activeEvents.foldLeft(false) {
case (false, FooEvent) => true
case (true, BarEvent) => false
case (prev, _) => prev
}
}
}
// now the trait can coordinate the implementation, and cascading dependencies are more clear to the reader.
trait Aggregate extends StuffWeNeed with Formulae {
def storedEvents: Seq[StoredEvent]
lazy val activeEvents = getActiveEvents(storedEvents);
lazy val isFoo = getIsFoo(activeEvents)
}
// And we can backfill new tests calculations without a dependency on long lists of events, but on the actual logic
val subjectUnderTest = new Formulae {}
subjectUnderTest.getIsBar(foo=true, barRule=ThisWasCalculatedElsewhere).shouldBe(false)
有什么想法吗?这仅仅是增加了并发症和流失率,还是代表着真正的改善?是将这些东西混合在一起的合适之处吗?