在 上一篇专栏文章中,我们首先讨论了数据验证方面的问题,这是企业应用程序设计的基本组件之一。在快速检查了 数据格式验证和 特定于业务的验证这两种类型的数据验证之后,我们讨论了这两种验证逻辑在应用程序代码中最有利的布局。在结束时我们针对数据格式和特定于业务的验证,提出了很好且有效的解决方案,但我们没有真正解决您在这一编程领域可能会遇到的更复杂情况。
特别是对于数据格式验证代码,我们认为处理它的最佳方法是使它接近客户机,这样可以使处理开销保持最少。因为示例应用程序包含了一个业务委派类,所以我们在其中放置了验证逻辑。这个布局产生的问题是它会在您的代码中引入许多冗余。
在本篇技巧文章中,我们将再次讨论数据格式验证,介绍数据验证助手类,它将让我们使验证过程接近客户机,同时不会引入任何不必要的代码。
对跨多个业务委派中的多个业务方法使用相同的数据类型作为参数,这是十分常见的。例如,可以将一本书的 ISBN 传递给
Inventory 委派的搜索方法和
Payment 委派的采购方法。如果将验证逻辑与这两个业务委派(象上一篇技巧文章中的那样)联系在一起,那么最终这两个方法中都会有 ISBN 验证代码。
改进数据格式验证过程的第一步是将所有的验证逻辑都移至一个助手类中,其它方法可以按需从这个类上调用验证逻辑。这种合并不仅减少了代码冗余,而且当我们需要时,能够维护和更改应用程序的数据格式。
要实现这样的合并,我们将使用
Validator 类,它为我们需要验证的各种数据类型简单地提供了静态方法。清单 1 显示了这样一个类的框架:
注:可以从诸如业务委派等其它类上调用清单 1 中的简单方法,以按需执行验证逻辑。还要注意这些方法 不返回布尔值。
清单 1. Validator 框架
package com.ibm.validation;
import java.util.Iterator;
import java.util.List;
public class Validator {
public static void validateISBN(String isbn)
throws InvalidDataException {
// Check the data type, and throw an error if
// needed
}
public static void validateIPAddress(String ipAddress)
throws InvalidDataException {
// Check data type
}
public static void validateUPC(String upc)
throws InvalidDataException {
// Check data type
}
public static void validateUPC(float upc)
throws InvalidDataException {
validateUPC(new String(upc));
}
public static void validateList(List list, Class class)
throws InvalidDataException {
for (Iterator i = list.iterator(); i.hasNext(); ) {
Object obj = i.next();
if !(obj instanceof class) {
throw new InvalidDataException("This list only " +
"accepts objects of type " +
class.getName());
}
}
}
}
|
清单 2 显示了一种有点杂乱的代码,这是使用布尔返回值产生的结果。
清单 2. 在 Validator 中使用布尔返回值
public boolean checkout(List books) throws ApplicationException {
if (Validator.validateList(books, Book.class)) {
try {
return library.checkout(books);
} catch (RemoteException e) {
throw new ApplicationException(e);
}
}
}
public Book lookup(String isbn) throws ApplicationException {
if (Validator.validateISBN(isbn)) {
try {
return library.lookup(isbn);
} catch (RemoteException e) {
throw new ApplicationException(e);
}
}
}
|
在更复杂的方法中,上述嵌套甚至会变得更为杂乱。通过允许抛出异常,我们已避免了这种杂乱所产生的额外复杂性,并使代码保持更“整洁”。另外,请注意
InvalidDataException 继承了
ApplicationException 。这允许所有委派方法的特征符保持不变,因而也允许通过相同机制来抛出任何验证异常。我们不必向方法特征符添加其它
throws 子句,也不必向方法主体添加其它
try/catch 块。简而言之,它使代码保持整洁和简单,而不会到处充斥括号、应用程序异常、验证异常以及
if/then 和
try/catch 块。
针对我们需要验证的特定数据类型,在将
Validator 置于适当位置并对它作设置之后,在应用程序中使用它就很容易,在我们的业务委派方法中尤其如此。清单 3 中重写了上一篇技巧文章中的委派,以使它能使用新的
Validator 类。
清单 3. 业务委派中的数据格式验证
package com.ibm.library;
import java.rmi.RemoteException;
import java.util.Iterator;
import java.util.List;
import javax.ejb.CreateException;
import javax.naming.NamingException;
import com.ibm.validation.Validator;
import com.ibm.validation.InvalidDataException;
public class LibraryDelegate implements ILibrary {
private ILibrary library;
public LibraryDelegate() {
init();
}
public void init() {
// Look up and obtain our session bean
try {
LibraryHome libraryHome =
(LibraryHome)EJBHomeFactory.getInstance().lookup(
"java:comp/env/ejb/LibraryHome", LibraryHome.class);
library = libraryHome.create();
} catch (NamingException e) {
throw new RuntimeException(e);
} catch (CreateException e) {
throw new RuntimeException(e);
} catch (RemoteException e) {
throw new RuntimeException(e);
}
}
// No validation required for accessor (getter) methods
public boolean checkout(Book book) throws ApplicationException {
// No validation required here; the object type
// takes care of it
try {
return library.checkout(book);
} catch (RemoteException e) {
throw new ApplicationException(e);
}
}
public boolean checkout(List books) throws ApplicationException {
// Validate list
Validator.validateList(books, Book.class);
try {
return library.checkout(books);
} catch (RemoteException e) {
throw new ApplicationException(e);
}
}
public Book lookup(String isbn) throws ApplicationException {
// Validate ISBN
Validator.validateISBN(isbn);
try {
return library.lookup(isbn);
} catch (RemoteException e) {
throw new ApplicationException(e);
}
}
// And so on...
public void destroy() {
// In this case, do nothing
}
}
|
使用独立的
Validator 使代码更模块化和更易维护。另外,我们已将所有的验证逻辑移至一处,从而避免代码中出现冗余。其结果是一个更佳、更不易出错的应用程序。
在本系列的下一篇技巧文章中,我们将研究验证的另一方面:异常处理。那时网上见。
- 您可以参阅本文在 developerWorks 全球站点上的
英文原文.
- 查阅由 Brett McLaughlin 撰写的完整的
EJB 最佳实践
系列。
- “
Enterprise JavaBean 基础”教程(
developerWorks,2001 年 3 月)是开始了解 EJB 技术的极佳途径。
- Eric Allen 的
诊断 Java 代码
专栏是一个技巧仓库,它帮助您管理 Java 代码中的常见错误。
- 在 Java 架构设计师 Srikanth Shenoy 的文章“
EJB 异常处理的最佳做法”(
developerWorks,2002 年 5 月)中,他演示了如何编码以快速解决基于 EJB 技术的系统的问题。
- Sun Microsystems 的
EJB 技术主页是掌握 EJB 技术信息的很好的起点。
- 还有一个极佳资源:
TheServerSide.com,它提供了有关 J2EE 的文章和信息。
- 有关 developerWorks 上与 EJB 技术和 J2EE 相关的免费教程列表,请参阅
developerWorks Java 技术教程页。
- 在
developerWorksJava 技术专区
查找成百篇 Java 技术资料。

Brett McLaughlin 自 Logo 时代(还记得那个小三角吗?)起就一直从事计算机方面的工作。目前他致力于通过使用 Java 以及与 Java 相关的技术构建应用程序基础结构。近几年他在 Nextel Communications 和 Allegiance Telecom, Inc 从事这些基础结构的实现。Brett是 Java Apache 项目 Turbine 的共同创始人之一,该项目为使用 Java servlet 的 Web 应用程序开发构建可重用的组件体系结构。他还是 EJBoss 项目(一个开放源码 EJB 应用程序服务器)和 Cocoon(开放源码 XML Web 发布引擎)的志愿开发人员之一。可以通过 brett@oreilly.com与 Brett 联系。