【IT168 技术文章】
合并验证逻辑
对跨多个业务委派中的多个业务方法使用相同的数据类型作为参数,这是十分常见的。例如,可以将一本书的 ISBN 传递给 Inventory 委派的搜索方法和 Payment 委派的采购方法。如果将验证逻辑与这两个业务委派(象上一篇技巧文章中的那样)联系在一起,那么最终这两个方法中都会有 ISBN 验证代码。
改进数据格式验证过程的第一步是将所有的验证逻辑都移至一个助手类中,其它方法可以按需从这个类上调用验证逻辑。这种合并不仅减少了代码冗余,而且当我们需要时,能够维护和更改应用程序的数据格式。
要实现这样的合并,我们将使用 Validator 类,它为我们需要验证的各种数据类型简单地提供了静态方法。清单 1 显示了这样一个类的框架:
注:可以从诸如业务委派等其它类上调用清单 1 中的简单方法,以按需执行验证逻辑。还要注意这些方法 不返回布尔值。
清单 1. Validator 框架
2 import java.util.Iterator;
3 import java.util.List;
4 public class Validator {
5 public static void validateISBN(String isbn)
6 throws InvalidDataException {
7
8 // Check the data type, and throw an error if
9 // needed
10 }
11
12 public static void validateIPAddress(String ipAddress)
13 throws InvalidDataException {
14
15 // Check data type
16 }
17 public static void validateUPC(String upc)
18 throws InvalidDataException {
19
20 // Check data type
21 }
22
23 public static void validateUPC(float upc)
24 throws InvalidDataException {
25
26 validateUPC(new String(upc));
27 }
28
29 public static void validateList(List list, Class class)
30 throws InvalidDataException {
31
32 for (Iterator i = list.iterator(); i.hasNext(); ) {
33 Object obj = i.next();
34 if !(obj instanceof class) {
35 throw new InvalidDataException("This list only " +
36 "accepts objects of type " +
37 class.getName());
38 }
39 }
40 }
41 }
42
清单 2 显示了一种有点杂乱的代码,这是使用布尔返回值产生的结果。
清单 2. 在 Validator 中使用布尔返回值
2 if (Validator.validateList(books, Book.class)) {
3 try {
4 return library.checkout(books);
5 } catch (RemoteException e) {
6 throw new ApplicationException(e);
7 }
8 }
9 }
10
11 public Book lookup(String isbn) throws ApplicationException {
12 if (Validator.validateISBN(isbn)) {
13 try {
14 return library.lookup(isbn);
15 } catch (RemoteException e) {
16 throw new ApplicationException(e);
17 }
18 }
19 }
20
在更复杂的方法中,上述嵌套甚至会变得更为杂乱。通过允许抛出异常,我们已避免了这种杂乱所产生的额外复杂性,并使代码保持更“整洁”。另外,请注意 InvalidDataException 继承了 ApplicationException 。这允许所有委派方法的特征符保持不变,因而也允许通过相同机制来抛出任何验证异常。我们不必向方法特征符添加其它 throws 子句,也不必向方法主体添加其它 try/catch 块。简而言之,它使代码保持整洁和简单,而不会到处充斥括号、应用程序异常、验证异常以及 if/then 和 try/catch 块。
使用 Validator
针对我们需要验证的特定数据类型,在将 Validator 置于适当位置并对它作设置之后,在应用程序中使用它就很容易,在我们的业务委派方法中尤其如此。清单 3 中重写了上一篇技巧文章中的委派,以使它能使用新的 Validator 类。
清单 3. 业务委派中的数据格式验证
2 import java.rmi.RemoteException;
3 import java.util.Iterator;
4 import java.util.List;
5 import javax.ejb.CreateException;
6 import javax.naming.NamingException;
7 import com.ibm.validation.Validator;
8 import com.ibm.validation.InvalidDataException;
9 public class LibraryDelegate implements ILibrary {
10 private ILibrary library;
11 public LibraryDelegate() {
12 init();
13 }
14
15 public void init() {
16 // Look up and obtain our session bean
17 try {
18 LibraryHome libraryHome =
19 (LibraryHome)EJBHomeFactory.getInstance().lookup(
20 "java:comp/env/ejb/LibraryHome", LibraryHome.class);
21 library = libraryHome.create();
22 } catch (NamingException e) {
23 throw new RuntimeException(e);
24 } catch (CreateException e) {
25 throw new RuntimeException(e);
26 } catch (RemoteException e) {
27 throw new RuntimeException(e);
28 }
29 }
30
31 // No validation required for accessor (getter) methods
32
33 public boolean checkout(Book book) throws ApplicationException {
34 // No validation required here; the object type
35 // takes care of it
36
37 try {
38 return library.checkout(book);
39 } catch (RemoteException e) {
40 throw new ApplicationException(e);
41 }
42 }
43
44 public boolean checkout(List books) throws ApplicationException {
45 // Validate list
46 Validator.validateList(books, Book.class);
47
48 try {
49 return library.checkout(books);
50 } catch (RemoteException e) {
51 throw new ApplicationException(e);
52 }
53 }
54
55 public Book lookup(String isbn) throws ApplicationException {
56 // Validate ISBN
57 Validator.validateISBN(isbn);
58
59 try {
60 return library.lookup(isbn);
61 } catch (RemoteException e) {
62 throw new ApplicationException(e);
63 }
64 }
65
66 // And so on...
67
68 public void destroy() {
69 // In this case, do nothing
70 }
71 }
72
使用独立的 Validator 使代码更模块化和更易维护。另外,我们已将所有的验证逻辑移至一处,从而避免代码中出现冗余。其结果是一个更佳、更不易出错的应用程序。