值列表处理程序模式


值列表处理程序提供搜索和迭代功能。要执行搜索,值列表处理程序使用数据访问对象来执行查询并从数据库中检索匹配的结果。

问题
您有一个想要遍历大型结果列表的远程客户端。

动因

  • 您希望避免使用EJB finder方法进行大型搜索的开销。
  • 您希望实现不需要事务的只读用例。
  • 您希望在大型结果集上为客户端提供有效的搜索和迭代机制。
  • 您希望在服务器端维护搜索结果。
  •  

解决方案
使用值列表处理程序搜索,缓存结果,并允许客户端遍历并从结果中选择项目。值列表处理程序提供搜索和迭代功能。要执行搜索,值列表处理程序使用数据访问对象来执行查询并从数据库中检索匹配结果。对于将业务对象作为实体bean实现的应用程序,这将绕过使用EJB查找器。

结构
让我们使用UML类图表示解决方案的基本结构,本节中的UML序列图介绍了解决方案的动态机制。 

类图

序列图


参与者与职责
Client  -  客户端是需要执行返回大量结果的查询的任何客户端。客户端可以是想要向用户显示搜索结果的表示层组件。客户端也可以是封装ValueListHandler的会话bean 。
ValueListIterator -  ValueListIterator提供了一种迭代机制,使用以下方法迭代ValueList的内容。
ValueListHandler -  ValueListHandler执行搜索并获取查询结果,它在由valuelist对象表示的私有集合中管理查询结果。ValueListHandler通常使用数据访问对象创建和操作ValueList集合。当客户端请求结果时,ValueListHandler从原始ValueList创建一个子列表并将其发送到客户端。通常,ValueListHandler管理单个ValueList。但是,如果必须组合和处理多个搜索结果,ValueListHandler可以管理多个ValueList实例。
DataAccessObject -  该ValueListHandler使用DataAccessObject访问数据源,执行查询和检索结果。
ValueList-  值列表是保存查询结果的集合。通常,您可以使用Java Collections API中的List实现,或根据您的需要实现自己的自定义List。
Value -  值表示搜索中的结果数据对象。

实施
考虑一个示例,检索并显示业务对象的列表。在这种情况下,您可以使用值列表处理程序。
ProjectsListHandler类,负责提供Projects列表。此类扩展了ValueListHandler基本抽象类,它提供了值列表处理程序的通用实现。

第1步:创建  ProjectTO  类

public class ProjectTO {
    private String projectId;
    private String projectName;
    private String managerId;
    private Date startDate;
    private Date endDate;
    private boolean started;
    private boolean completed;
    private boolean accepted;
    private Date acceptedDate;
    private String customerId;
    private String projectDescription;
    private String projectStatus;

    public String getProjectId() {
        return projectId;
    }

    public void setProjectId(String projectId) {
        this.projectId = projectId;
    }

    public String getProjectName() {
        return projectName;
    }

    public void setProjectName(String projectName) {
        this.projectName = projectName;
    }

    public String getManagerId() {
        return managerId;
    }

    public void setManagerId(String managerId) {
        this.managerId = managerId;
    }

    public Date getStartDate() {
        return startDate;
    }

    public void setStartDate(Date startDate) {
        this.startDate = startDate;
    }

    public Date getEndDate() {
        return endDate;
    }

    public void setEndDate(Date endDate) {
        this.endDate = endDate;
    }

    public boolean isStarted() {
        return started;
    }

    public void setStarted(boolean started) {
        this.started = started;
    }

    public boolean isCompleted() {
        return completed;
    }

    public void setCompleted(boolean completed) {
        this.completed = completed;
    }

    public boolean isAccepted() {
        return accepted;
    }

    public void setAccepted(boolean accepted) {
        this.accepted = accepted;
    }

    public Date getAcceptedDate() {
        return acceptedDate;
    }

    public void setAcceptedDate(Date acceptedDate) {
        this.acceptedDate = acceptedDate;
    }

    public String getCustomerId() {
        return customerId;
    }

    public void setCustomerId(String customerId) {
        this.customerId = customerId;
    }

    public String getProjectDescription() {
        return projectDescription;
    }

    public void setProjectDescription(String projectDescription) {
        this.projectDescription = projectDescription;
    }

    public String getProjectStatus() {
        return projectStatus;
    }

    public void setProjectStatus(String projectStatus) {
        this.projectStatus = projectStatus;
    }
}

第2步:实现值列表处理程序:  ProjectListHandler。

public class ProjectListHandler extends ValueListHandler {

    private ProjectDAO dao = new ProjectDAO();
    // use ProjectTO as a template to determine
   
// search criteria
    private ProjectTO projectCriteria = null;

   
// Client creates a ProjectTO instance, sets the 
   
// values to use for search criteria and passes 
   
// the ProjectTO instance as projectCriteria
   
// to the constructor and to setCriteria() method
    public ProjectListHandler(ProjectTO projectCriteria)
    throws Exception {
        try {
            this.projectCriteria = projectCriteria;
            executeSearch();
        } catch (Exception e) {
           
// Handle exception, throw ListHandlerException
        }
    }

    public void setCriteria(ProjectTO projectCriteria) {
        this.projectCriteria = projectCriteria;
    }

   
// executes search. Client can invoke this
   
// provided that the search criteria has been
   
// properly set. Used to perform search to refresh
   
// the list with the latest data.
    public void executeSearch()
    throws Exception {
        try {
            if (projectCriteria == null) {
                throw new Exception(
                   
"Project Criteria required...");
            }
            List resultsList =
                dao.executeSelect(projectCriteria);
            setList(resultsList);
        } catch (Exception e) {
           
// Handle exception, throw ListHandlerException
        }
    }
}

第3步:实现  GenericValueListHandler  类
该ValueListHandler是一个通用的迭代类,它提供了迭代功能。

public class ValueListHandler
implements ValueListIterator {

    protected List list;
    protected ListIterator listIterator;

    public ValueListHandler() {}

    protected void setList(List list)
    throws IteratorException {
        this.list = list;
        if (list != null)
            listIterator = list.listIterator();
        else
            throw new IteratorException("List empty");
    }

    public Collection getList() {
        return list;
    }

    public int getSize() throws IteratorException {
        int size = 0;

        if (list != null)
            size = list.size();
        else
            throw new IteratorException(
"No data found"); //No Data

        return size;
    }

    public Object getCurrentElement()
    throws IteratorException {

        Object obj = null;
       
// Will not advance iterator
        if (list != null) {
            int currIndex = listIterator.nextIndex();
            obj = list.get(currIndex);
        } else
            throw new IteratorException(
"");
        return obj;

    }

    public List getPreviousElements(int count)
    throws IteratorException {
        int i = 0;
        Object object = null;
        LinkedList list = new LinkedList();
        if (listIterator != null) {
            while (listIterator.hasPrevious() && (i < count)) {
                object = listIterator.previous();
                list.add(object);
                i++;
            }
        }
// end if
        else
            throw new IteratorException(
"No data found"); // No data

        return list;
    }

    public List getNextElements(int count)
    throws IteratorException {
        int i = 0;
        Object object = null;
        LinkedList list = new LinkedList();
        if (listIterator != null) {
            while (listIterator.hasNext() && (i < count)) {
                object = listIterator.next();
                list.add(object);
                i++;
            }
        } else
            throw new IteratorException(
"No data found"); // No data

        return list;
    }

    public void resetIndex() throws IteratorException {
        if (listIterator != null) {
            listIterator = list.listIterator();
        } else
            throw new IteratorException(
"No data found"); // No data
    }

}

第4步:创建  ProjectDAO 类。

public class ProjectDAO {
    final private String tableName = "PROJECT";

   
// select statement uses fields
    final private String fields =
"project_id, name," +
       
"project_manager_id, start_date, end_date, " +
       
" started, completed, accepted, acceptedDate," +
       
" customer_id, description, status";

   
// the methods relevant to the ValueListHandler
   
// are shown here.
   
// See Data Access Object pattern for other details.
   
// ...
    public List < ProjectTO > executeSelect(ProjectTO projCriteria)
    throws SQLException {

        PreparedStatement stmt = null;
        List < ProjectTO > list = null;
        Connection con = getConnection();
        StringBuffer selectStatement = new StringBuffer();
        selectStatement.append(
"SELECT " + fields +
           
" FROM " + tableName + "where 1=1");

       
// append additional conditions to where clause
       
// depending on the values specified in 
       
// projCriteria
        if (projCriteria.getProjectId() != null) {
            selectStatement.append(
" AND PROJECT_ID = '" +
                projCriteria.getProjectId() +
"'");
        }
       
// check and add other fields to where clause
       
//...

        try {
            stmt = con.prepareStatement(selectStatement.toString());
            stmt.setString(1, projCriteria.getProjectId());
            ResultSet rs = stmt.executeQuery();
            list = prepareResult(rs);
            stmt.close();
        } finally {
            con.close();
        }
        return list;
    }

    private Connection getConnection() {
       
// TODO Auto-generated method stub
        return null;
    }

    private List < ProjectTO > prepareResult(ResultSet rs)
    throws SQLException {
        List < ProjectTO > list = new ArrayList();
        while (rs.next()) {
            int i = 1;
            ProjectTO proj = new ProjectTO();
            proj.setProjectName(rs.getString(i++));
            proj.setManagerId(rs.getString(i++));
            proj.setStartDate(rs.getDate(i++));
            proj.setEndDate(rs.getDate(i++));
            proj.setStarted(rs.getBoolean(i++));
            proj.setCompleted(rs.getBoolean(i++));
            proj.setAccepted(rs.getBoolean(i++));
            proj.setAcceptedDate(rs.getDate(i++));
            proj.setCustomerId(rs.getString(i++));
            proj.setProjectDescription(rs.getString(i++));
            proj.setProjectStatus(rs.getString(i++));
            list.add(proj);

        }
        return list;
    }

   
// implement other stuff
   
//...
}

第5步:ValueListIterator 接口

import java.util.List;
//http://www.oracle.com/technetwork/java/valuelisthandler-142464.html
public interface ValueListIterator {
    public int getSize() throws IteratorException;

    public Object getCurrentElement() throws IteratorException;

    public List getPreviousElements(int count) throws IteratorException;

    public List getNextElements(int count) throws IteratorException;

    public void resetIndex() throws IteratorException;

   
// other common methods as required
   
// ...
}

第6步:创建  自定义异常  类。

public class IteratorException extends Exception {

    public IteratorException(String message) {
        super(message);
    }

}


后果

  • 提供EJB查找器的有效替代方案
  • 缓存搜索结果
  • 提供灵活的搜索功能
  • 提高网络性能
  • 允许延迟实体bean事务
  • 促进关注点的分层和分离
  • 创建大型传输对象列表可能很昂贵