假设您有一首歌的域模型类。歌曲有一个速度属性(一个整数),它应该总是一个正数。该要求是否应该是域模型的一部分或外部(例如在SongManager /业务逻辑层类中)?
假设你选择像这样实现它:
class Song {
private int tempo;
// ...
public void setTempo(int tempo) {
if (tempo > 0) {
this.tempo = tempo;
} else {
// what?
}
}
}
您可以使用以下内容替换// what?
:
s
,s.setTempo(-10)
根本不会修改对象的状态。1
。setTempo
子句中将选中 throws InvalidTempoException
和throw
标记为else
。这样,控制器或其他组件负责捕获无效的速度值并决定如何处理异常。我问,因为我最近一直在探索常见的“分层架构”方法,特别是域层。
答案 0 :(得分:2)
歌曲的节奏属性(一个int)应该始终是一个 正数
如果这是正确初始化Song
的要求,那么你应该抛出相应的例外,例如IllegalArgumentException
答案 1 :(得分:2)
此要求是否应该是域模型的一部分或外部(例如在SongManager /业务逻辑层类中)?
域相关逻辑应该存在于域模型中。以管理员身份调用通常表示您不知道在何处放置代码以及如何正确命名代码。
无。给定一个Song实例s,s.setTempo(-10)根本不会修改对象的状态。
如果您需要尝试来设置速度,并且如果您无法控制将要传递的参数,则忽略设置速度的失败是可以接受的。就像使用UDP协议一样 - 如果失败就没问题。只有我会相应地命名 - 比如s.trySetTempo(-10)。
将速度设定为某个最小值,例如1。
这就像第一种情况的延伸。只有当需要将歌曲速度默认设置为接近零时,我才能想到任何商业案例。
使用已检查的标记setTempo会抛出InvalidTempoException并将其抛出到else子句中。这样,控制器或其他组件负责捕获无效的速度值并决定如何处理异常。 抛出运行时InvalidTempoException。
抛出异常意味着任何试图设置速度的东西都要对正确的输入负责,因为永远不会有预期的异常。通常你也必须编写canSetTempo(或类似isTempoChangeable之类的)指示器方法,以便外界可以在尝试真实交易之前点击它。
将tempo属性提取到Tempo类中,其中包含“必须大于0”。
这取决于您的域的形状。如果其他任何东西(如SoundSample类,MidiClip类)需要使用速度概念,这可能是一个好主意。另外 - 如果它几乎与您的业务无关并且只是在Song类中污染更有趣的逻辑,那么封装速度可能会很好。
我个人喜欢,如果操作可用,域模型会提供答案,但操作本身会抛出错误。这也可以使用更好的用户体验。负责改变速度的字段和按钮不会出现/被禁用 - 立即反馈说明还有一些事情无法完成。
答案 2 :(得分:1)
如果Song
无法使用零或负速度值,那么这肯定应该是Song
内建模的不变量。
如果尝试了无效值,您应该抛出异常 - 这可以确保您没有Song
处于无效状态。