赛迪网 > IT技术 IT技术重磅推荐 > 文章
  IT资讯搜索
 
IT产品搜索
[程序开发][网管世界][网络安全][数据库技术]
[操作系统][嘉宾聊天·在线访谈][活动集锦]
[精彩专题][Symantec专区][订阅IT技术周刊]
[开发论坛][网管论坛][安全论坛][数据库论坛]
[操作系统论坛][Sybase专区][IBM dW技术专区]
[病毒求助][病毒与漏洞播报][文档·源码下载]

浅析设计模式中的Iterator迭代器

发布时间:2008.01.09 09:07     来源:赛迪网    作者:执木

 

在Pet Store中的CatalogDao使用了DAO模式,从而完成Fast-Lane Reader模式,以便能快速的输出数据库元素列表,同时使用for page-by-page iteration完成每页的输出显示。

在CatalogDAOImpl 中基本返回的是Page,也就是说,在CatalogDAOImpl的具体JDBC数据库查询时,就将Page功能融入其中,从而一步到位的完成输出显示。

但在实际系统应用中,我们都有用户权限约束,也就是说,并不是每条数据库记录都能被显示输出,有些用户就只能看到他被授权看到的的记录。

Jive中的Iterator模式就很好的解决了这个问题,Jive中使用Proxy模式完成用户权限级别的验证,同时为了更快的获得数据库记录和节约内存,Jive专门建立了自己的Iterator模式,这些一开始让人疑惑,直接使用Collection的Iterator不是更好,虽然简单方便了,但是前提是在内存中要先开辟一块Collection内存,如果数据库记录很大,将耗费很多内存,致使系统瘫痪

Jive的Iterator不只是传递了数据库指针,而且加载了权限验证功能,因此,这一模式是实用可行的,那么在我们自己的EJB应用中如何综合这两个系统的模式优点?

这其中应该有很多中间方案可行,如果你有兴趣可以贴出你的想法,我目前采取的是DAO模式和Jive的Iterator模式集合,也就是说,在自己的EJB中不直接返回Page 而是返回Iterator,这个Iterator是类似Jive中的DatabaseObjectIterator。

简单的说,由于Jive不是EJB架构,所以,将Jive中的访问数据库段用DAO模式替代,其他都可以照搬Jive的Iterator模式,关于前端JSP页面的分页输出,这时可以参考Pet Store的page-by-page iteration模式,也就是说,根据Iterator模式再拓展写Page,结构和功能类似Pet store的Page.

这里只提供一个大体思路,如果要写透彻真是很长,看看平常我们以前用ASP PHP做的数据库查询分页的简单功能蕴含这么多新的思想,其实这些思想也是在ASP PHP应付大数据库量失败的总结,所以软件质量控制是显得多么重要。

 

我用Iterator的程序代码:
public interface DataListIterator
{
    /**
     * 功能类似于java.util.Iterator.hasNext()
     *
     * @return 如果有下一个元素,返回true
     * @throws Exception
     */
    public boolean hasNext() throws Exception;

    /**
     * 功能类似于java.util.Iterator.next(),但是返回的是数据库查询的结果
     * 的字段值字符串数组。
     *
     * @return String[] 字段值字符串数组
     * @throws Exception
     */
    public String[] next() throws Exception;
}

 

public interface DataList{

    /**
     * 取出指定位置查询结果中的字段值,放到一个字符串数组中并返回。
     * 功能类似于java.util.List.get(int)
     *
     * @param index 查询结果的索引
     * @return String[] 结果中的字段值数组
     *
     * @throws Exception
     */
    public String[] get(int index) throws Exception;

    /**
     * 检查查询结果的集和是否为空集合
     *
     * @return boolean true表示空集合
     * @throws Exception
     */
    public boolean isEmpty() throws Exception;

    /**
     * 检查是否还有下一个查询结果
     *
     * @return boolean true表示有下一个
     * @throws Exception
     */
    public boolean hasNext() throws Exception;

    /**
     * 检查在指定位置上是否有查询结果
     *
     * @param index 查询结果的索引
     * @return boolean true表示有查询结果
     * @throws Exception
     */
    public boolean isElementExist(int index) throws Exception;

    /**
     * 把游标放到指定的位置上,功能类似于java.sql.ResultSet.absolute(int)
     *
     * @param index 指定的位置,从0开始
     * @return boolean true表示操作成功
     * @throws Exception
     */
    public boolean absolute(int index) throws Exception;

    /**
     * 把游标放到查询结果的最前面,功能类似于java.sql.ResultSet.beforeFirst()
     *
     * @throws Exception
     */
    public void beforeFirst() throws Exception;

    /**
     * 把游标放到查询结果的第一个,功能类似于java.sql.ResultSet.first()
     *
     * @return boolean true表示移动成功
     * @throws Exception
     */
    public boolean first() throws Exception;

    /**
     * 把游标放到查询结果的最后一个,功能类似于java.sql.ResultSet.last()
     *
     * @return boolean true表示移动成功
     * @throws Exception
     */
    public boolean last() throws Exception;

    /**
     * 取得整个查询结果的大小,功能类似于java.util.List.size()
     *
     * @return size 查询结果的大小
     * @throws Exception
     */
    public int size() throws Exception;

    /**
     * 提供一个可以遍历查询结果的对象,功能类似于java.util.List.iterator()
     *
     * @return DataListIterator 可以遍历查询结果的对象
     * @throws Exception
     */
    public DataListIterator iterator() throws Exception;


}

 

 

 


public interface DataListHandler{

    /**
     * 得到查询结果的一个子集
     *
     * @param startIndex 子集的起始位置
     * @param count 子集的个数
     * @return Datalist 返回一个子集
     * @throws Exception
     */
    public DataList getListChunk(int startIndex, int count) throws Exception;

    /**
     * 取得整个查询结果的大小,功能类似于java.util.List.size()
     *
     * @return size 查询结果的大小
     * @throws Exception
     */
    public int size() throws Exception;

    /**
     * 检查子集的前面是否还有查询结果
     *
     * @return boolean true表示前面还有查询结果
     */
    public boolean hasPrevious();

    /**
     * 检查子集的后面是否还有查询结果
     *
     * @return boolean true表示后面还有查询结果
     * @throws Exception
     */
    public boolean hasNext() throws Exception;

    /**
     * 关闭对象
     * @throws Exception
     */
    public void close() throws Exception;
}

 

 

 

* @version 1.0
 *
 * Page实现了DataListHandler。
 *
 * 用于操作ResultSetDataList对象,对查询结果集进行分页显示。在进行显示的期间,必须
 * 保持数据库连接Connection和结果集ResultSet没有关闭。
 * 基本使用方法举例:
 *  *              int index = 4, count = 10;//显示第5到第14条记录
 *              Connection conn = Pool.getConnection();
 *              //(1)使用一个QueryDAO的具体子类来初始化页对象
 *              ResultSetQueryDAO dao = new ResultSetQueryDAO();
 *              ResultSetPage page = new ResultSetPage(conn, dao);
 *
 *              //(2)或者直接使用一个ResultSet对象来初始化页对象
 *              //ResultSet rs = ...;
 *              //ResultSetPage page = new ResultSetPage(conn, rs);
 *
 *              //需要显示的当前页chunk
 *              DataList chunk = page.getListChunk(index, count);
 *              //当前页的前后是否还有记录,用于显示PRVEIOUS和NEXT按钮
 *              boolean hasPrevious = page.hasPrevious();
 *              boolean hasNext = page.hasNext();
 *              //遍历显示当前页的记录
 *              DataListIterator it = chunk.iterator();
 *              while (it.hasNext())
 *              {
 *                  String[] valuesOfRow = it.next();
 *                  for(int i = 0; i < valuesOfRow.length; i++)
 *                      System.out.println(valuesOfRow[i]);
 *              }
 *
 *
 *
 * @see QueryDAO
 * @see DataListIterator
 */

import java.sql.*;

public class ResultSetPage implements DataListHandler{

    private Connection conn = null;
    private ResultSet rs = null;
    private ResultSetDataList dl = null;
    private RowMapper mapper = null;
    private QueryDAO dao = null;
    private int indexOfDataList = 0, countPerPage = 0;

    /**
     * 构造函数,提供用于查询的DAO具体对象。
     *
     * @param conn 数据库连接
     * @param dao 用于查询的DAO具体对象
     * @throws SQLException
     *
     */
    public ResultSetPage(Connection conn, QueryDAO dao) throws SQLException
    {
        this.conn = conn;
        //使用使用DAO具体对象查询
        this.rs = (ResultSet)dao.doQuery(conn);
        initiateDataList();
    }

    /**
     * 构造函数,直接提供查询的结果集。
     *
     * @param conn 数据库连接
     * @param rs 查询的结果集
     * @throws SQLException
     */
    public ResultSetPage(Connection conn, ResultSet rs) throws SQLException
    {
        this.conn = conn;
        this.rs = rs;
        initiateDataList();
    }

    /**
     * 得到被查询的字段名称数组
     *
     * @return String[] 字段名称数组
     */
    public String[] getColumns()
    {
        return mapper.getRowColumns();
    }

    /**
     * 得到查询结果的一个子集
     *
     * @param startIndex 子集的起始位置, 从0开始
     * @param count 子集的个数
     * @return Datalist 返回一个子集
     * @throws Exception
     */
    public DataList getListChunk(int startIndex, int count) throws Exception
    {
        if(dl == null)
            throw new Exception("还没有执行查询或者查询过程出现异常!");

        indexOfDataList = Math.abs(startIndex);
        countPerPage = Math.abs(count);
        return new ResultSetDataListChunk(dl, indexOfDataList, countPerPage);
    }

    /**
     * 取得整个查询结果的大小,功能类似于java.util.List.size()
     *
     * @return size 查询结果的大小
     * @throws SQLException
     */
    public int size() throws SQLException
    {
        if(dl == null)
            throw new SQLException("还没有执行查询或者查询过程出现异常!");
        return dl.size();
    }

    /**
     * 检查子集的前面是否还有查询结果
     *
     * @return boolean true表示前面还有查询结果
     */
    public boolean hasPrevious()
    {
        if(indexOfDataList == 0)
            return false;
        else
            return true;
    }

    /**
     * 检查子集的后面是否还有查询结果
     *
     * @return boolean true表示后面还有查询结果
     * @throws SQLException
     */
    public boolean hasNext() throws SQLException
    {
        if(indexOfDataList + countPerPage >= dl.size())
            return false;
        else
            return true;
    }

    /**
     * 关闭对象
     * @throws SQLException
     */
    public void close() throws SQLException
    {
        if(rs != null)
        {
            rs.close();
            rs = null;
        }
        if(conn != null)
        {
            conn.close();
            conn = null;
        }
        mapper = null;
    }

    /**
     * helper方法,设置印射,生成包含结果计的ResultSetDataList对象
     *
     * @throws SQLException
     */
    private void initiateDataList() throws SQLException
    {
        //设置印射,生成包含结果计的ResultSetDataList对象
        mapper = new ResultSetRowMapper(rs);
        dl = new ResultSetDataList(mapper, conn, rs);
    }
}

 

public interface QueryDAO{

     /**
      * 执行查询操作
      *
      * @param conn 数据库连接
      * @return Object 查询结果(ResultSet或者RowSet)。
      * @throws SQLException
      */
     public Object doQuery(java.sql.Connection conn) throws java.sql.SQLException;
}

 


在jsp/serlvet中调用:

      ResultSetPage groupPage = groupManager.groups();
      DataList chunk = groupPage.getListChunk(0, 50);  //chunk.size()

为结果集大小,可用于分页
      DataListIterator it = chunk.iterator();
               while (it.hasNext())
            {
       String[] valuesOfRow = it.next();

}

     (责任编辑:包春林)

 


[ 发表评论 ] 字体[  ] [ 打印 ] [ 进入博客 ] [ 进入论坛 ]  [ 推荐给朋友 ]
  相关文章
· 设计模式之Proxy (01-08) · 通过Struts应用MVC设计模型 (01-08)
· 设计模式之Bridge (01-08) · 谈学习GoF设计模式的重要性 (01-08)
· 高级:使用异步Servlet扩展AJAX应用程序 (01-08) · J2SE综合--区分eclipse中的两种JRE (01-08)
· Java入门--String中三种加法的区别 (01-08) · J2SE综合--java通过JNI与delphi交互 (01-08)
· 入门:JpetStore学习struts新的开发模式 (01-08)
  客户需求反馈表
* 姓  名:
更多资料  了解方案  认识厂商
* 单位名称:
* 联系电话:
* 电子邮件:
  赛迪推荐  
  手机·资费 ·新品·导购·评测·手机资费·宽带
手机搜索  诺基亚 N73 MOTO Z6
  IT产品 ·笔记本·台式机·服务器·打印·投影
IT产品搜索 
  IT技术 ·开发·网管·安全·数据库·操作系统
  信息化 ·热点·专题·访谈·周刊·方案案例
· 专家:从第三方法律服务看我国信息化法制建设
· 民营企业不上ERP会怎样? 必须贯彻一把手工程
· 排队时代电子银行如何补短板 银行信息化现状
· 信息化灾难降临时如何应对与善后 与灾难竞速
· IT部门应否实施预算制 CIO如何让信息中心站稳
· 公交一卡通不推行实名制 一卡多用可购物买药
  IT博客 ·曾剑秋·项立刚·Java学习·网管
  IT技术论坛 ·开发·网管·安全·数据库·系统