我来自 OO 背景(C#、javascript),Scala 是我第一次涉足 FP。
由于我的背景,我在实现一个非常适合我的领域问题并且符合 FP 的良好实践(例如代码中的最小可变性)的领域模型时遇到了困难。
首先,简要描述一下我现在的域问题。
- 主要领域对象是:
Event, Tournament, User, and Team
Teams
由Users
- 两者
Teams
都可以Users
参加Tournaments
Event
Events
包括Users
和Tournaments
- 得分、统计数据和排名,
Teams
以及Users
谁竞争Tournaments
,Events
将是一个主要特征。
鉴于对问题的描述,我对域的最初想法是创建对象,其中双向循环关系是常态——类似于图。我的思路是,能够访问任何给定对象的所有关联对象将为我提供最简单的数据视图编程和操作途径。
case class User(
email: String,
teams: List[TeamUser],
events: List[EventUser],
tournaments: List[TournamentUser]) {
}
case class TournamentUser(
tournament: Tournament,
user: User,
isPresent: Boolean){
}
case class Tournament(
game: Game,
event: Event,
users: List[TournamentUser],
teams: List[TournamentTeam]) {
}
然而,当我深入研究 FP 最佳实践时,我发现我的思维过程与 FP 原则不兼容。循环引用不受欢迎,对于不可变对象似乎几乎是不可能的。
鉴于此,我现在正在努力解决如何重构我的域以满足良好 FP 的要求,同时仍然保持域中“现实世界对象”的常识组织。
我考虑过的一些选项
- 使用惰性 val 和按名称引用——我对此的疑虑是,一旦域变得不平凡,这似乎变得难以管理
- 改用单向关系——虽然我被迫将一些域对象降级为只能通过其他对象访问的第二类对象,但使用这种方法。我会如何选择?它们对我来说似乎都同样重要。另外,这将需要构建“反对谷物”的查询,以获取第二类对象的简单列表。
- 使用间接并存储关系标识符列表——这消除了周期性依赖,但随后会产生更多复杂性,因为我必须编写额外的业务逻辑来模拟关系更新并额外访问数据库以获得任何关系。
所以我正在努力改变我的实现或我的原始模型以实现我认为我需要的耦合,但以“正确的方式”用于 Scala。我该如何解决这个问题?
TL;DR——当域似乎需要双向访问和核心可变性时,我如何使用良好的 FP 实践对域进行建模?