模式的三要素-问题,语境,解决方案我们在前面已经论述过了,每个模式都有它自己独特的价值观,那么这组架构模式给我们带来了什么?
首先,它将校验逻辑从应用逻辑中解耦出来,使得应用和校验器可以独立变化。第二,它促进了代码重用,校验器可以用到任何应用逻辑中去,不必局限于一处。如果需要的话,我们甚至可以将整个校验器当作一个横切关注点 (Crosscut concern),应用 AOP(Aspect of Programming)技术,将待校验数据当作 Pointcut,这样在应用的代码中会看不到任何校验代码的痕迹,这就彻底分离出了数据校验逻辑代码。第三,从应用场合来看,隔离校验器主要用在那些数据类型简单而且校验规则简单的数据校验中,可组装校验器用在那些数据类型复杂或校验规则复杂、多变的数据校验中,而动态策略校验器则用在同一个数据的校验就有多种校验规则策略的数据校验中。可以看到,这几种模式是根据待校验数据的粒度大小和业务规则的复杂程度来划分的。
接下来,我们研究一下模式的变体。可组装校验器是这组模式的核心,它有很多变体,其实动态策略校验器就是它的一种变体,其他变体还有复合规则检验器,链式检验器,动态注册检验器等。比如在 XML 校验器 SAX 的实现中,用户可以动态地插入校验 handle,或者我们需要对一个数据依次执行多套校验规则,而不像之前一次只有一个校验规则会被执行。对于这种需求,我们有三种方案可选,第一种是复合规则检验器,利用Composite 模式来实现校验规则 IVRule 接口,复合的校验规则类中包含一组简单的校验规则类 VRule,当调用复合类的 validate() 方法时,复合类会依次调用所有的简单校验规则类。第二种是链式校验器,利用 Chain of responsibility 模式来实现校验规则 IVRule 接口,前一个校验规则类执行校验后传递到下一个校验规则类,一层层按固定顺序传递下去,每一个校验规则类关注的校验点不一样,这适合于顺序固定的情况。第三种是动态注册校验器,利用 Registry 模式,将校验规则类 VRule 动态地注册到校验器类 Validator 中去,比如注册到一个 List 或 Map 中,在校验器类的 validate() 方法中可以按某种算法来实现调用校验规则类的顺序或更复杂的调用逻辑。很显然动态注册校验器很灵活,可扩展性也很强,但同时对校验器使用者来说,它复杂了,校验规则也不透明了。所以并非灵活性和可扩展性越强就越好,一切应该取决于需求,如果你一次只有一个校验规则执行就没必要再引入复杂性了。
另外还可以对校验方法的返回类型作一下扩展,boolean 值和异常作为返回一般来说足够了,但如果我们的返回结果比较复杂,比如前面讲到的一个数据需要执行多个校验规则的情况,返回的结果可能需要将多个校验规则的返回结果汇总,也可能需要更细级别的结果。这就需要一种工业级的返回机制,在 Eclipse 中就有这么一个返回类型,称为状况对象 (Status object),它可以对返回类型进行分级:OK、 Warning、 Error,甚至还封装了更低级的异常。而且针对返回状态比较复杂的情况,还应用了 Composite 模式实现了一个 MultiStatus 类来组合多个错误状态。这在校验结果不仅仅是 true 或 false 两种状态的场合下非常有用,而且可以记录跟踪校验规则信息。不过这是一种重量级的返回机制。下面展示了状况对象的接口代码:
//清单 10:IStatus.java
2
3 public static final int OK = 0;
4
5 public static final int INFO = 0x01;
6
7 public static final int WARNING = 0x02;
8
9 public static final int ERROR = 0x04;
10
11 //返回更低级的异常。
12
13 public Throwable getException();
14
15 //返回消息,如错误信息。
16
17 public String getMessage();
18
19 //返回状况类型,OK,INFO, WARNING,ERROR
20
21 public int getSeverity();
22
23 public boolean isOK();
24
25 //是否复合状况。
26
27 public boolean isMultiStatus();
28
29 //如果是复合状况,返回子状况类。
30
31 public IStatus[] getChildren();
32
33
结束语
这组架构模式不局限于某种语言、应用,可以应用到任何场合。如果我们将数据校验当作一项业务操作的话,可以将它扩展到其他领域。模式可以促进好的架构,也可能导致万劫不复,关键取决于设计者的把握。所以,我们在选择模式的时候,一定要考量模式的何种特性对你最有价值,模式所提供的价值观与您的需求期望是否吻合。
代码下载:DataValidator.jar