【问题标题】:OOP Design - Where/When do you Validate properties?OOP 设计 - 您在何处/何时验证属性?
【发布时间】:2010-04-09 18:47:10
【问题描述】:

我已经阅读了几本关于 OOP DDD/PoEAA/Gang of Four 的书籍,但似乎没有一本涉及验证主题 - 似乎总是假设数据是有效的。

我从这篇帖子 (OOP Design Question - Validating properties) 的回答中得知,客户端应该只尝试在域对象上设置 有效 属性值。

此人提出了一个类似的问题,但仍未得到解答:http://bytes.com/topic/php/answers/789086-php-oop-setters-getters-data-validation#post3136182

那么你如何确保它是有效的? 您是否在每个 getter 和 setter 旁边都有一个“验证器方法”?

  • isValidName()
  • setName()
  • getName()

我似乎遗漏了一些关于 OOP 数据验证的关键基础知识 - 你能告诉我一本详细介绍该主题的书吗? - IE。涵盖不同类型的验证/不变量/处理反馈/是否使用异常等

【问题讨论】:

标签: php validation oop


【解决方案1】:

每个对象都应确保其内部状态是一致的,因此最好在修改内部状态之前完成验证 - 在对象的 setter 方法中。

【讨论】:

    【解决方案2】:

    根据我的经验,验证发生在有人工/用户输入的地方。这通常发生在您允许通过您的方法更改某些内容的地方。在您的示例中,我将验证该方法:

    setName()
    

    所以它发生在你允许输入值/设置值的地方,结果是 setter 方法。

    【讨论】:

      【解决方案3】:

      OOP 的一个重要部分就是始终保持对象处于有效状态。因此,验证应该在可能修改对象的输入之后进行。

      验证来自属性/集、参数到函数和构造函数的数据总是好的。

      【讨论】:

      • “OOP 的一个重要部分是始终保持您的对象处于有效状态” - 我喜欢这个,谢谢。
      【解决方案4】:

      区分域对象不变量意义上的有效(必须始终满足)和某些人所说的“contextual validation."”是很重要的,例如,银行账户为负数的客户是否“无效?”不,但他们可能无权执行某些类型的交易。这是上下文验证,与“每个客户实体必须有一个非空 ID”相反,后者完全是一种不同类型的验证。

      一种强制执行不变量的有效技术是将代表用户输入的类与域对象区分开来,并且不要在域对象上公开不受限制的修改器(例如简单的集合访问器)。

      例如,如果您有一个Student 域对象,请不要直接在用户界面中操作它。您的视图不是创建 Student 实例,而是创建 StudentBuilder 实例,这些实例模拟您构建有效 Student 域对象所需的内容。

      接下来,您拥有验证构建器实例是否符合域对象的不变量的类,以及一个接受构建器并将它们转换为有效域对象的工厂。 (您也可以在这一步酌情引入上下文验证策略。)

      【讨论】:

      • 是的,这似乎是有道理的。我有一种通过创建“规范对象”或“数据笼”来保存传入数据的方式来做到这一点 - 但以前并不确定。
      【解决方案5】:

      如果您控制使用您的类的代码,那么您应该在尝试操作对象的变量之前进行验证(通过公共属性)。如果您预计您不知道如何使用您的类的情况,那么是的,您应该在属性内进行验证,这或多或少是它们的用途。显然,这假设“是有效名称”的定义是对象固有的静态业务规则。

      在这两个级别上进行验证当然是最安全的方法。

      【讨论】:

      • 是的,'isValid' 的定义也是一个相当混乱的领域。这个问题似乎需要一些上下文才能可靠 - 我发现自己在写这样的东西:Order->IsValidOrderAccordingToPaymentStrategy() 希望听到关于这个主题的经典书籍,除了我之外的每个人似乎都读过。
      • 在多个地方进行验证似乎是个坏主意。一方面,您需要维护重复的代码。另外,从概念上讲,如果你有一个 Cow 对象,牛应该知道什么构成了有效的食物输入——你不希望世界上的每一种植物都将自己验证为可接受的牛食。让母牛决定吧。
      • 但是你不一定想把你的奶牛放在一个到处都是毒蘑菇的牧场里,即使你有理由确定你的奶牛不会吃它们。 :)
      【解决方案6】:

      这取决于您的编程风格,因为 Wikipedia 有更详细的解释,所以我将只触及表面并链接到 Wikipedia。 (是的,我就是这么懒。:-))

      注意:所有这些都不适用于用户输入。您必须以任何一种方式对其进行验证。我只是在谈论不应以任何方式与用户输入耦合的业务逻辑类。 :-)

      • 防守

      正如其他人所提到的,您将强制执行每个属性。我经常抛出运行时异常 (Java) 来指示这些失败。

      Wikipedia on Defensive Programming

      • 根据合同

      您记录代码的要求并假设,例如,传递给您的设置器的值对于定义的合同是有效的。这可以为您节省大量样板代码。但是当给出非法值时,寻找错误会稍微困难一些。

      Wikipedia on Design by Contract

      【讨论】:

      • 我发现按合同设计 (TM) 信息非常有用——尤其是“努力失败”的想法,这似乎是所有这些答案的主题。让供应商的工作尽可能简单,让客户决定当价值被拒绝时该怎么做。
      【解决方案7】:

      简而言之,始终验证。总而言之,一次执行所有验证,而不是“一路”。这将有助于您的代码保持精简并有助于调试混乱。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-03-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-06-11
        • 1970-01-01
        相关资源
        最近更新 更多