【问题标题】:Should the factory pattern contain validation logic工厂模式是否应该包含验证逻辑
【发布时间】:2013-04-25 17:24:36
【问题描述】:
当使用工厂模式时,工厂本身是否应该包含验证逻辑,还是应该留给调用类在传递上下文数据之前处理验证?
我有一个简单的工厂方法,但它依赖于传递给它的配置树来决定要实例化的对象。
可能存在这样一种情况,即配置 xml 格式可能正确,但不是工厂期望的正确格式,我不知道应该在哪里进行验证。
【问题讨论】:
标签:
java
design-patterns
factory
【解决方案1】:
当使用工厂模式时,工厂本身是否应该包含验证逻辑,还是应该留给调用类在传递上下文数据之前进行验证?
组织验证有两种不同的选择:
- 验证作为一个单独的过程
有一个单独的验证方法Validate(Config)。此方法在构造方法之前调用,并返回Config 是否有效的信息。如果Validate 方法返回Config 有效,则调用构造方法。构建过程中出现任何错误均视为异常。
- 作为构建过程一部分的验证
没有单独的验证方法。而是在需要时在构造方法内部进行验证。 允许构造方法失败并返回构造对象或指示错误的结果。
第二个变体可以使用 monad 很好地实现,代码和性能开销几乎为零。
【解决方案2】:
验证是什么意思?是什么让您认为作为工厂设计模式实例的一部分的代码与任何其他代码不同?
如果验证是指检查从用户或输入文件读取的输入值,答案是否:解析输入的代码负责验证,而不是随后使用的工厂读取值。
如果通过验证您的意思是让 Factory 的工厂方法检查其调用者提供的值是否符合这些方法的先决条件,则答案与对其参数施加先决条件的任何其他方法相同:共识Java 的风格是用于检查其先决条件的方法,如果不满足先决条件,则抛出合适的RuntimeException。
现在,实际上,这意味着某些输入值将被检查两次。首先是输入验证码,然后是工厂的前置条件检查。部分原因是将代码分解为模块(这里是单独的输入模块和服务层)的成本。
但它也允许检查以更适合其目的的不同方式报告。
- 前置条件检查失败(在本例中为工厂)表明程序中存在错误。我们希望在更改程序状态之前快速而准确地报告前置条件失败,以获得最有用的调试信息(在许多情况下,错误的位置将是调用堆栈中的一个方法)。
- 对于输入验证失败,我们通常希望程序在输入的一次解析中报告尽可能多的错误,以便用户可以修复所有错误。想想你使用的编译器:如果它在你的源代码中发现第一个语法错误后停止,你会很沮丧。抛出异常来实现这一点是不合适的。如果可能,代码应该记录错误并继续解析,而不是在程序中弹出到更高级别的部分(这就是引发异常的行为)。
【解决方案3】:
为什么不两者都提供?这样,您就可以将关于他是否希望他的输入验证或不验证的责任传递给调用者。
从 Apache Commons 获取这个示例 - InstantiateFactory:
它的默认构造函数不提供验证:
InstantiateFactory(java.lang.Class classToInstantiate)
执行无验证的构造函数。
但在getInstance 中提供验证:
静态工厂getInstance(java.lang.Class classToInstantiate, java.lang.Class[] paramTypes, java.lang.Object[] args)
执行验证的工厂方法。