J2EE有针对此问题的规范JSR303,建议在实体中进行合法性的校验。为什么这样做呢?官方给出的理由是:既然在展现层、逻辑层、持久层都需要进行重复的校验,为什么不集中在实体上进行统一的校验,省时省力,多好呀!
显然,这个理由有一定的说服力。但其前提是什么呢?前提是将展现层的事情,在服务端完成;数据的约束,放在持久层完成,也是在服务端完成。
我个人不这么认为,
第一个理由:展现层的约束应该交给应用端,而持久层的约束应该交给数据库(数据表字段的约束设计)。服务端关注业务逻辑上的校验,至于展现约束与存储约束,不是该他做的事情;这样才有利于使业务模型更干净和清晰。(服务端只关注数据与逻辑的处理)
第二个理由:对与错,好与坏,脱离语境(上下文)是不能冒然下定论的,直接将验证逻辑绑定在实体上,无异于直接给一个人贴上好人或坏人,庸才或天才的标签。
你所引用的文章的主要观点,与我的第二个理由相同,支持在业务场景中进行合法性的校验:
1)Think about that question, “is this entity valid”. You can’t answer that question unless you know the context for validation.
2)And that’s where I think we should move towards in terms of validation. Instead of answering the question, “is this object valid”, try and answer the question, “Can this operation be performed?”.
此外,合法性的校验是异常设计的一个重要部分,无法回避,甚至需要花不少的精力进行精心的设计。试以最为常见的空指针异常为例,空指针异常是一种运行时异常(unchecked exception),在服务端的校验中时常需要将其包装为编译时异常(checked exception),并在业务场景进行捕获,以响应状态码为400的响应返回应用端;而应用端的空指针异常,则反之,时常仍包装为运行时异常,在最靠近用户的地方捕获该异常,并以友好的提示信息呈现给用户。
当然,如果项目已经采用了服务端的展现框架,比如GWT、JSF、ZK之类的,开发者迫于进度的压力,管它什么干净、清晰的业务模型,按时交工,才是重之重,或许在实体上绑定校验逻辑,是上上之策,这是事实,也很难回避。