【问题标题】:Should my Domain Objects have an isValid() method to return the current state of the object? [closed]我的域对象是否应该有一个 isValid() 方法来返回对象的当前状态? [关闭]
【发布时间】:2013-02-24 09:45:08
【问题描述】:

我最近将表单数据验证移至模型层,特别是在域对象设置器中(这是对还是错?)。当我在我的User 服务中并且我这样做时

$user->setFirstName($firstName);

并且输入太长(超过 25 个字符)我是否应该将域对象中的某种 state 变量设置为不稳定(可能 = 0)并在模型中设置错误消息以便在视图中检索?

我会通过运行isValid() 方法来检查视图中对象的状态。

这是正确的做法吗?

谢谢。

【问题讨论】:

标签: php oop model-view-controller


【解决方案1】:

这更像是一个架构问题,并且有很多答案。 Grails web framework 采用与此类似的方法,但会自动将 validate() 添加到域对象中。 CodeIgniter has you roll your own similar.

就我个人而言,我喜欢将验证逻辑放入 setter/constructors 并在我的先决条件不满足时抛出异常。这意味着,您的用户必须确保他们输入有效数据或在不输入有效数据时显式处理,而不是让您的视图必须询问对象是否有效。

【讨论】:

  • 感谢您的回复。除了遇到问题外,我试图在例外情况下做到这一点。例如,在UserService 中,我在User 域对象中设置了 firsName 和 lastName。我设置了名字,没有例外,我设置了姓氏,它会抛出一个LengthException。当我捕捉到该异常时,我知道它是LengthException,但我不知道该异常是针对哪个字段引发的。我不想使用字段名称设置异常消息,因为显然您永远不应该向用户/客户端显示异常消息。你如何解决这个问题?
  • 您应该在抛出异常时设置异常消息,并提供一些信息。如果您不想将消息显示给客户,您自己可以随时以编程方式阅读它并“做一些有趣的事情”(例如以红色突出显示文本)。
  • 所以让我们说如果没有提供姓氏,在我的setLastName() 中我会抛出一个InvalidArgumentException('lastName') 然后当我捕捉到我的异常时,我可以通过catch(InvalidArgumentException $ex) { $field = $ex->getMessage() } 和现在我知道哪个字段引发了异常?这是正确的吗?
  • 是的,应该这样做。
  • @tereško 同样在这篇文章中:stackoverflow.com/questions/15040979 您在帖子顶部说“setter 不应该验证数据”,然后您说我有两个验证选项,其中之一是“验证在每个二传手中”,然后在底部说“二传手中的验证只是可行的解决方案。”在我上面的这篇文章中,您说“当您有多个绑定参数时,setter 上的数据验证失败。”。我应该从中得到什么?举个例子就明白了,我已经看到了足够多的没有实现的文章,这就是我在这里的原因。
【解决方案2】:

我想说 form 验证与域对象无关。如果提交的表单无效,通常根本没有理由创建/修改域对象,这完全是表示层/用户界面的问题。将用户输入验证放入域对象中违反了关注点分离原则。

但是,这是一个有争议的问题,没有绝对正确或错误的方法。因为如果您想确保域对象不能处于无效状态(在构造函数和设置器中抛出异常),您最终可能会得到重复的代码。

但是,如果您在域对象中使用验证来进行表单验证,您应该更喜欢异常而不是isValid 状态。对象应始终处于有效状态,这是 OOP 的一大优势

更新

关于输入验证的问题:我为每个控制器使用专门的请求对象,并在控制器中使用它们,如下所示:

try {
    $user = $this->request->extractUserFromPost();
} catch (ValidationException $e) {
    $this->showValidationError($e->getMessage(), $e->getAffectedFields());
}

这些方法也可以在控制器本身中,但我更喜欢包含尽可能少的自身逻辑的瘦控制器。另一种常见的方法是在一个地方管理表单的生成和验证的表单对象(例如:Zend\Form)。如果请求总是来自表单,这是有道理的。我上面的示例适用于 Web 服务以及 HTML 用户界面。

【讨论】:

  • 你会把所说的验证放在哪里不违反它?在控制器中?在请求抽象中?在存储抽象中?
  • 我更新了答案。
  • 你知道什么是“域对象”,它的职责是什么?
  • 是的。你在暗示什么?
猜你喜欢
  • 2013-08-06
  • 2016-09-19
  • 1970-01-01
  • 2017-09-10
  • 2015-08-29
  • 1970-01-01
  • 2012-10-08
  • 2021-06-21
  • 1970-01-01
相关资源
最近更新 更多