重构具有可变性和循环依赖性的域模型,以便为Scala提供良好的FP实
我来自OO背景(C#,javascript),Scala是我第一次涉足FP.
由于我的背景,我无法很好地实现适合我的域问题的域模型,并且还符合FP的良好实践,例如代码中的最小可变性. 首先,简要描述我现在的域名问题. >主要域对象包括:事件,锦标赛,用户和团队 鉴于问题的这种描述,我对域的最初想法是创建对象,其中双向循环关系是常态 – 类似于图形.我的想法是,能够访问任何给定对象的所有关联对象将为我提供最简单的路径,为我的数据编程视图,以及操纵它. 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原则不相容. Circular references are frowned upon,似乎差不多是impossibility with immutable objects. 鉴于此,我现在正在努力解决如何重构我的域以满足良好FP的要求,同时仍然保持域中“真实世界对象”的常识组织. 我考虑过的一些选择 > Use lazy val and by-name references – 我对此的疑虑是,一旦域变得不平凡,似乎变得无法管理 因此,我正在努力改变我的实现或我的原始模型,以实现我认为我需要的耦合,但是对于Scala来说是“正确的方式”.我该如何处理这个问题? TL; DR – 当域似乎要求双向访问和核心可变性时,如何使用良好的FP实践对域建模? 解决方法
假设您的域模型由数据库支持,在上面突出显示的情况下,我会创建User类defs的“团队”,“事件”和“锦标赛”属性,从数据库中检索相应的对象(您如果你担心过多的db调用,可以实现一个缓存策略.它可能看起来像:
case class User(email: String)) { def teams = TeamService.getAllTeams.filter( { t => t.users.contains(this) } ) //similar for events and tournaments } 另一种说法可能是您的循环依赖关系具有单一的“权威”方向,而另一方向的引用则由此计算.这样,例如,当您将用户添加到锦标赛时,您的功能只需返回一个新的锦标赛对象(添加了用户),而不是新的锦标赛对象和新的用户对象.此外,Tournament可以简单地包含User / Boolean元组列表,而不是显式建模TournamentUser链接表. 另一个选择可能是使用Lenses来修改您的域模型,但我没有在这种情况下实现它们.也许在FP方面有更多经验的人可以在这里说出他们的适用性. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |