Mat*_*can 8 functional-programming scala immutability domain-model cyclic-reference
我来自OO背景(C#,javascript),而Scala是我第一次涉足FP.
由于我的背景,我无法很好地实现适合我的域问题的域模型,并且还符合FP的良好实践,例如代码中的最小可变性.
首先,简要描述我现在的域名问题.
Event, Tournament, User, and TeamTeams 由...组成 UsersTeams并Users可以参加Tournaments这发生在一个EventEvents由Users和组成TournamentsTeams和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]) {
}
Run Code Online (Sandbox Code Playgroud)
然而,随着我进一步深入FP最佳实践,我发现我的思维过程与FP原则不相容.循环引用是不受欢迎的,似乎几乎不可能与不可变对象.
鉴于此,我现在正在努力解决如何重构我的域以满足良好FP的要求,同时仍然保持域中"真实世界对象"的常识组织.
我考虑过的一些选择
因此,我正在努力改变我的实现或原始模型,以实现我认为我需要的耦合,但对于Scala来说是"正确的方式".我该如何处理这个问题?
TL; DR - 当域似乎要求双向访问和核心的可变性时,如何使用良好的FP实践对域建模?
小智 2
假设您的域模型由数据库支持,在上面突出显示的情况下,我将使您的 User 类定义的“团队”、“事件”和“锦标赛”属性从数据库中检索适当的对象(您如果您担心过多的数据库调用,可以实施缓存策略)。它可能看起来像:
case class User(email: String)) {
def teams = TeamService.getAllTeams.filter( { t => t.users.contains(this) } )
//similar for events and tournaments
}
Run Code Online (Sandbox Code Playgroud)
另一种说法可能是,您的循环依赖项具有单个“权威”方向,而另一个方向的引用是据此计算的。这样,例如,当您将用户添加到锦标赛时,您的函数只需返回一个新的锦标赛对象(包含添加的用户),而不是一个新的锦标赛对象和一个新的用户对象。此外,锦标赛可以简单地包含用户/布尔元组的列表,而不是显式地对 TournamentUser 链接表进行建模。
另一种选择可能是使用Lenses来修改您的域模型,但我还没有在这种情况下实现它们。也许在 FP 方面有更多经验的人可以在这里谈谈它们的适用性。
| 归档时间: |
|
| 查看次数: |
539 次 |
| 最近记录: |