【问题标题】:Should persistent objects validate data upon set?持久对象是否应该在设置时验证数据?
【发布时间】:2009-09-09 09:45:56
【问题描述】:
如果有一个对象可以在执行过程中保持自身(无论是使用 ORM 的数据库,还是使用 Python 的 shelve 模块等),该对象属性的验证应该放在代表它的类中,还是放在外面?
或者,更确切地说;持久对象应该是哑并期望设置它的值是仁慈的,还是应该智能并验证分配给它的数据?
我不是在谈论类型验证或用户输入验证,而是影响持久对象的事物,例如存在对其他对象的链接/引用,确保数字是无符号的,日期没有超出范围等。
【问题讨论】:
标签:
language-agnostic
orm
oop
persistence
【解决方案1】:
验证是封装的一部分——一个对象负责它的内部状态,而验证是它的内部状态的一部分。
这就像问“我应该让一个对象执行一个函数并设置他自己的变量,还是我应该让 getter 来获取它们,在外部函数中完成工作,然后你 setter 将它们设置回来?”
当然你应该使用一个库来完成大部分的验证——你不想在每个模型中实现“检查无符号值”功能,所以你在一个地方实现它并让每个模型在他的适合自己的代码。
【解决方案2】:
对象应验证数据输入。否则,分配数据的应用程序的每个部分都必须应用相同的测试集,并且检索持久数据的应用程序的每个部分都需要处理其他模块未正确完成检查的可能性。
顺便说一句,我不认为这是面向对象的。它适用于任何需要输入的数据持久性构造。基本上,您说的是按合同设计的前提条件。
【解决方案3】:
我的策略是,为了使全局代码健壮,每个对象 A 都应该尽可能早地检查。但“尽可能”需要解释:
-
每个字段的内部一致性 A 中的 B(类型、类型范围等)应由字段类型 B 本身检查。如果是原始字段,或者重用类,是不可能的,所以A对象应该检查一下。
-
相关字段的一致性(如果 B 字段为空,则 C 也必须为空)是对象 A 的典型职责。
-
字段 B 与 A 外部的其他代码的一致性是另一回事。这就是“pojo”方法(在 Java 中,但适用于任何语言)发挥作用的地方。
POJO 方法表明,由于我们在现代软件中承担的所有责任/顾虑(持久性和验证只是其中的两个),域模型最终会变得混乱且难以理解。问题在于,这些领域对象对于理解整个应用程序、与领域专家交流等都是至关重要的。每次您必须阅读域对象代码时,您都必须处理所有这些问题的复杂性,而您可能不关心或只关心一个......
因此,在 POJO 方法中,您的域对象不得携带与这些关注点之一相关的代码(通常携带要实现的接口或要拥有的超类)。
除了领域一之外的所有关注点都在对象之外(但仍然可以提供一些简单的信息,在 java 中通常通过注释来参数化处理一个关注点的通用外部代码)。
此外,域对象仅与其他域对象相关,而不与与某个关注点(例如验证或持久性)相关的某些框架类相关。因此,可以将包含所有类的域模型放入单独的“包”(项目或其他)中,而不依赖于技术或与关注相关的代码。这使得理解复杂应用程序的核心变得更加容易,而没有这些次要方面的所有复杂性。