Design patterns DDD-无域服务的有条件业务规则

Design patterns DDD-无域服务的有条件业务规则,design-patterns,domain-driven-design,Design Patterns,Domain Driven Design,假设您有一个简单的聚合根,如下所示: Playlist { String name List<Song> songs add(Song song) { // Some business rules songs.add(song) } } 播放列表{ 字符串名 列出歌曲 添加(歌曲){ //一些商业规则 歌曲。添加(歌曲) } } 现在假设您想在依赖于其他聚合根的add(Song)方法中引入一个业务规则。例如:一首歌曲不能出现在3个以上的播放列表

假设您有一个简单的聚合根,如下所示:

Playlist {
  String name
  List<Song> songs

  add(Song song) {
    // Some business rules

    songs.add(song)
  }
}
播放列表{
字符串名
列出歌曲
添加(歌曲){
//一些商业规则
歌曲。添加(歌曲)
}
}
现在假设您想在依赖于其他聚合根的
add(Song)
方法中引入一个业务规则。例如:一首歌曲不能出现在3个以上的播放列表中。一种方法是在应用层获取此信息(包含歌曲的播放列表的数量),并将其传递给
add(song)
方法

但是现在进一步假设这个业务规则只在某些条件下适用。例如,假设名称以“M”开头的播放列表没有这样的限制(完全任意)。现在,在应用层获取信息意味着要么在错误的级别实现域逻辑,要么获取不使用的数据。随着业务规则变得越来越复杂,成本也越来越高

现在显而易见的解决方案是:使用一个可以访问播放列表存储库的域服务,并在那里执行您的逻辑。虽然这是可行的,但我想知道是否有任何模式/架构提示/重组可以在不使用服务封装逻辑的情况下解决这个问题

谢谢

我知道你说“没有服务”,但我决定列出我能想到的解决这个问题的所有方法(不是所有等效方法):

  • AR方法接收纯外部数据。正如您所说,这是最简单的策略,但对于更复杂的场景来说有点不足。它还将AR与特定种类的歌曲播放列表添加规则相耦合

  • AR方法接收策略/规则。AR方法提供了执行规则的策略(可能是不纯的)。例如,您可以有一个
    歌曲播放添加规则#检查(歌曲,播放列表)
    界面。
    Playlist
    AR只需调用
    规则。检查(歌曲,这个)
    即可强制执行。应用层将利用某种规则提供程序来获取适当的规则,或者通过IoC容器注入正确的规则

  • 域服务。这一点很明显,无法解释

  • 同步策略(事件处理程序)应用于同一事务。您将拥有一个
    songplaylayadditionpolicy
    ,它通过内存中的
    DomainEventPublisher
    侦听类似于
    songplaylist
    的事件,从而允许策略参与/执行同一事务。
    SongPlayAssociationPolicy
    将位于域中。它类似于#2和#3,但间接调用

  • 最终一致的政策。与上面的概念相同,但将在另一个事务中异步执行。您很可能会允许违规,但随后会通知用户,由于违反了策略或任何其他类型的补偿操作,歌曲已从播放列表中删除

  • 传奇/流程管理器。您可以将此方法视为保留模式,在该模式中,您将引入向最终目标移动的小的、强一致的过渡状态。每个状态转换通常在它自己的事务中处理,并在发生故障时通过补偿操作回滚。e、 g

    a)
    播放列表。添加(歌曲)
    ⟶ 激发
    SongAddedToPlaylist
    /throws:检查播放列表特定的不变量(例如,播放列表中的最大歌曲数)

    b)
    song.apply(songdaddetoplaylist)
    ⟶ 激发
    SongAdditiontoPlaylist确认
    /
    SongAdditiontoPlaylist失败
    :检查特定于歌曲的不变量(例如,它属于多少播放列表)

  • 需要注意的是,在上述所有检查中,#1、#2、#3和可能的#4都可能是过时的检查,这意味着它们不一定能够通过并发防止违反规则,除非您以某种方式锁定给定事务中读取的所有数据

    #5可以与#1-#4结合使用,以减少意外违反的数量,但也包括通过并发违反规则的场景

    #6可能是最自然的一个,因为从域名的角度来看,它几乎都是ARs。如果您不想处理最终的一致性,您可以始终以类似于#4的方式进行集成,并在单个TX中修改所有AR。在这种情况下,您也不必对过渡状态进行建模。然后,当您需要进行扩展时,您将转向最终的一致性

    希望这能给你一些关于如何有效解决你的具体问题的想法!没有适合所有人的解决方案