谈谈设计模式中的Iterator迭代器

2008-05-24 05:33:49.0     浏览:120     来源:天新网
关键词:  ER  

在阅读本文之前,你需要了解Pet Store的J2EE模式


(http://Java.sun.com/blueprints/patterns/catalog.html)


在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内存,如果


数据库记录很大,将耗费很多内存,致使系统瘫痪(细节讨论见

http://www.jdon.com:81/jive/thread.JSP?forum=16&thread=302)


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();


}


作者简介:

21岁,大学计算机系专业,现正致力于JAVA开发,对JAVA的桌面应用系统开发和Web相关技术有一定研究,曾开发jant,jzip,小型游戏,JDBC..etc,对J2EE/J2ME充满信心。

你可以通过网站:http://www.fls-cts.com/kkjvk/、 OICQ:29578635,878229,email:kkjvk12@yeah.net和vincent联系。