1

假设您有一个 Song 的域模型类。歌曲有一个速度属性(一个 int),它应该总是一个正数。这个需求应该是领域模型的一部分还是外部的(例如在 SongManager / 业务逻辑层类中)?

假设您选择这样实现它:

class Song {
  private int tempo;
  // ...

  public void setTempo(int tempo) {
    if (tempo > 0) {
      this.tempo = tempo;
    } else {
      // what?
    }

  }

}

您是否将// what?上面替换为:

  1. 没有。给定一个 Song 实例ss.setTempo(-10)根本不会修改对象的状态。
  2. 将速度设置为某个最小值,例如1.
  3. 在子句setTempo中用选中 throws InvalidTempoException的和throw它标记。else这样,控制器或其他组件负责捕获无效的速度值并决定如何处理异常。
  4. 抛出运行时InvalidTempoException。
  5. 将 tempo 属性提取到 Tempo 类中,其中封装了“必须大于 0”。
  6. 别的东西。

我问是因为我最近一直在探索常见的“分层架构”方法,尤其是领域层。

4

3 回答 3

2

歌曲有一个速度属性(一个 int),它应该总是一个正数

如果这是正确初始化的要求,Song那么您应该抛出相应的异常,例如IllegalArgumentException

于 2012-05-20T19:56:40.013 回答
2

这个需求应该是领域模型的一部分还是外部的(例如在 SongManager / 业务逻辑层类中)?

领域相关的逻辑应该存在于领域模型中。将某些东西称为经理通常表明您只是不知道在哪里放置代码以及如何正确命名它。

没有。给定一个 Song 实例 s,s.setTempo(-10) 根本不会修改对象的状态。

如果您需要尝试设置速度并且您对将要传递的参数几乎没有控制权,那么忽略设置速度的失败是可以接受的。就像 UDP 协议一样——如果它失败了也没关系。只有我会相应地命名它 - 类似于 s.trySetTempo(-10)。

将速度设置为某个最小值,例如 1。

这就像第一个案例的扩展。只有当需要将歌曲速度默认接近零时,我想不出任何商业案例。

用选中的 throws InvalidTempoException 标记 setTempo 并将其抛出到 else 子句中。这样,控制器或其他组件负责捕获无效的速度值并决定如何处理异常。抛出运行时 InvalidTempoException。

抛出异常意味着任何试图设置节奏的东西都负责正确的输入,因为不应该出现预期的异常。通常,您还必须编写 canSetTempo(或类似 isTempoChangeable 之类的)指标方法,以便外部世界可以在尝试实际交易之前点击它。

将 tempo 属性提取到 Tempo 类中,其中封装了“必须大于 0”。

这取决于您的域的形状。如果其他任何东西(如 SoundSample 类、MidiClip 类)需要使用速度的概念,这可能是一个好主意。另外 - 如果它与您的业务几乎无关并且只会污染 Song 类中更有趣的逻辑,那么封装节奏可能会很好。


我个人喜欢当域模型提供答案时,如果操作可用,但操作本身会引发错误。这也可以制作更好的用户体验。负责改变速度的字段和按钮不会出现/被禁用 - 立即反馈某些事情还不能完成。

于 2012-05-22T07:41:58.130 回答
1

如果 aSong对于零或负速度值无效,则这当然应该是在 内建模的不变量Song

如果尝试了无效值,您应该抛出异常 - 这可以确保您没有Song处于无效状态。

于 2012-05-20T19:57:41.067 回答