【问题标题】:Simple domain objects attribute values简单的域对象属性值
【发布时间】:2012-05-20 19:53:28
【问题描述】:

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

假设您选择这样实现它:

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

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

  }

}

你能把上面的// what?替换成:

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

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

【问题讨论】:

  • 虽然#3 的味道很明显(必须捕获或躲避每个setTempo 调用的检查异常),但有一种方法可以利用它,使躲避的异常基本上“冒泡”到一些验证层?

标签: oop dns domain-driven-design ooad


【解决方案1】:

Song 有一个 tempo 属性(一个 int),它应该始终是一个 正数

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

【讨论】:

  • 在 Java 中,IllegalArgumentException 是运行时异常。我知道这是合理的(这是 IllegalArgumentException 的意图),但为什么不抛出一个检查异常来确保它被捕获呢?
  • 这不应该被抓住。如果Song 应该具有特定的不变量以便被视为正确初始化,那么这应该是运行时异常
【解决方案2】:

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

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

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

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

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

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

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

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

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

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


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

【讨论】:

  • 检查异常的另一个缺陷:任何调用 setTempo 的方法都难以捕捉或回避异常。
  • @ybakos 我觉得这不是真的。不应发生异常。如果他们这样做 - 一个全局处理程序就足够了。
【解决方案3】:

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

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

【讨论】:

  • @ybakos - 我以独立于语言的方式回答,因为您没有用特定语言标记您的问题。根据您的评论,我猜您是在询问 Java 实现。对于那种特定的语言,我没有答案。但是,当属性存在并且可能被修改时,这会在 运行时 发生。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多