本文来自李明子csdn博客(http://blog.csdn.net/free1985),商业转载请联系博主获得授权,非商业转载请注明出处!
迭代器(Iterator)模式提供了不暴露对象内部状态的情况下依序遍历集合中元素的方法。
从应用场景来说,迭代器既可用于对集合中不可访问对象的保护也可用于对访问顺序的控制,本教程中的示例属于后者。
通常来说,遍历算法有两个可选的实现的位置。一个是在迭代器内部实现,本教程中的示例就属于这种情况;另一个是由集合自身实现,此时,迭代器仅对集合中对象的访问状态进行记录,迭代器仅作为游标使用。
结合图2-1,下面介绍各类在迭代器设计模式中扮演的角色。
3.1 Aggregate
Aggregate是集合接口,声明了迭代器对象创建方法CreateIterator。在JAVA中,已经定义了Aggregate接口,即java.lang.Iterable,迭代器对象的创建方法为iterator。
3.2 ConcreteAggregate
ConcreteAggregate是具体集合类,实现了Aggregate接口。在JAVA中,即为实现了java.lang.Iterable接口的类。其中,iterator方法返回的迭代器对象为具体迭代器类对象。
3.3 Iterator
Iterator是迭代器接口,声明了迭代器应实现的各方法。在JAVA中,已经定义了Iterator接口,即java.util.Iterator。通过对比不难发现,java.util.Iterator中声明的方法与2-1的类图中声明的方法不尽相同。类图中声明的迭代器可以重用,即可以通过First方法重置迭代器,且不包含任何对集合中元素的处理方法;java.util.Iterator不包含类似First这种重置迭代器的方法,且包含移除最后访问元素的方法remove。两种形式的设计理念略有不同,对应不同的应用场景各有利弊。笔者认为,从重用和封装的角度来讲,2-1类图中描述的接口更为合理和明晰。在实际应用中我们也可以根据实际需要声明自己的迭代器接口。
3.4 ConcreteIterator
ConcreteIterator是具体迭代器类,实现了Iterator接口。在JAVA中,即为实现了java.util.Iterator接口的类。为了实现对集合的遍历,ConcreteIterator类需要维护其要遍历的集合的引用。另外,拥有较好健壮性的迭代器应该可以支持遍历过程中集合元素的增删改等变化。
3.5 Client
Client是客户类,是迭代器模式的使用者。Client构建集合对象,并调用其CreateIterator方法创建迭代器对象。再使用迭代器对象遍历集合。
下面我们用一个业务场景实例来进一步讲解迭代器的使用。
4.1 场景介绍
某银行柜台排队系统根据一定的策略对请求进行排队处理。请求按照VIP用户优先;存款业务优先;先到先处理三个条件排序。
以下各节将介绍该场景各类的具体实现及其在迭代器设计模式中所对应的参与者角色。
4.2 UserRequest
UserRequest是用户请求类,声明了用户请求中的编号、用户是否为VIP、请求业务类型及请求时间等属性。UserRequest在迭代器模式类图中未出现,它是集合中的元素。下面的代码给出了UserRequest的声明。
package demo.designpattern.iterator;
import java.util.Date;
/**
* 用户请求
* Created by LiMingzi on 2017/8/8.
*/
public class UserRequest{
/**
* 请求编号
*/
private String requestCode;
/**
* 是否为vip用户
*/
private boolean isVip;
/**
* 请求类型,0为存款;1为取款
*/
private int type;
/**
* 请求时间
*/
private Date requestDate;
/**
* 构造方法
* @param requestCode 请求码
* @param isVip 是否为vip
* @param type 请求类型,0为存款;1为取款
*/
public UserRequest(String requestCode, boolean isVip, int type) {
this.requestCode = requestCode;
this.isVip = isVip;
this.type = type;
this.requestDate=new Date();
}
/**
* 获取请求码
* @return 请求码
*/
public String getRequestCode() {
return requestCode;
}
/**
* 获取是否为VIP
* @return 是否为VIP
*/
public boolean isVip() {
return isVip;
}
/**
* 获取请求类型
* @return 请求类型,0为存款;1为取款
*/
public int getType() {
return type;
}
/**
* 获取请求日期
* @return 请求日期
*/
public Date getRequestDate() {
return requestDate;
}
@Override
public String toString() {
// 请求类型
String typeString;
if(type==0){
typeString="存款";
}else if(type==1){
typeString="取款";
}else{
typeString="其他";
}
// 请求信息
String requestInfo = "请"+requestCode+"号";
if(this.isVip){
requestInfo+="VIP";
}
requestInfo+="顾客到柜台办理"+typeString+"业务-"+this.requestDate;
return requestInfo;
}
}
4.3 UserRequestList
UserRequestList是用户请求集合,提供了对UserRequest类型对象集合的维护。UserRequestList实现了java.lang.Iterable接口。对应于迭代器模式的参与者,UserRequestList是具体集合类ConcreteAggregate。下面的代码给出了UserRequestList的声明。
package demo.designpattern.iterator;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* 用户请求链表
* Created by LiMingzi on 2017/8/8.
*/
public class UserRequestList implements Iterable {
/**
* 用户请求链表
*/
private List userRequests = new ArrayList();
/**
* Returns an iterator over a set of elements of type T.
*
* @return an Iterator.
*/
@Override
public Iterator iterator() {
return new UserRequestIterator(userRequests);
}
/**
* 添加用户请求
* @param userRequest 用户请求
*/
public void add(UserRequest userRequest){
userRequests.add(userRequest);
}
}
上述代码中,15行,声明了用户请求对象集合userRequests,通过将其声明为私有成员且不提供对应的访问器和public操作方法,我们仅能通过30行声明的add方法向其添加用户请求。23行,返回的UserRequestIterator类型的迭代器对象是遍历userRequests的唯一方法。
4.4 UserRequestIterator
UserRequestIterator是用户请求迭代器,用于遍历UserRequestList维护的UserRequest对象集合。UserRequestIterator实现了java.util.Iterator接口。对应于迭代器模式的参与者,UserRequestIterator是具体迭代器类ConcreteIterator。下面的代码给出了UserRequestIterator的声明。
package demo.designpattern.iterator;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
/**
* 用户请求迭代器
* Created by LiMingzi on 2017/8/8.
*/
public class UserRequestIterator implements Iterator {
/**
* 用户请求链表
*/
private List userRequests;
/**
* 上一个请求
*/
private UserRequest lastUserRequest;
/**
* 已遍历请求代码集合
*/
private ListdoneRequestCodes=new ArrayList();
/**
* 构造方法
* @param userRequests 用户请求链表
*/
public UserRequestIterator(List userRequests) {
this.userRequests = userRequests;
}
/**
* Returns true if the iteration has more elements. (In other
* words, returns true if next would return an element
* rather than throwing an exception.)
*
* @return true if the iterator has more elements.
*/
@Override
public boolean hasNext() {
return doneRequestCodes.size()/**
* Returns the next element in the iteration.
*
* @return the next element in the iteration.
* @throws NoSuchElementException iteration has no more elements.
*/
@Override
public Object next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
// 下一个请求
UserRequest nextUserRequest = null;
for (UserRequest userRequest : userRequests) {
// 该请求已遍历
if(doneRequestCodes.contains(userRequest.getRequestCode())){
continue;
}
// 还没有可比较请求
if(nextUserRequest==null){
nextUserRequest = userRequest;
continue;
}
if(compareUserRequest(userRequest,nextUserRequest)>0){
nextUserRequest=userRequest;
}
}
lastUserRequest = nextUserRequest;
doneRequestCodes.add(nextUserRequest.getRequestCode());
return nextUserRequest;
}
/**
* Removes from the underlying collection the last element returned by the
* iterator (optional operation). This method can be called only once per
* call to next. The behavior of an iterator is unspecified if
* the underlying collection is modified while the iteration is in
* progress in any way other than by calling this method.
*
* @throws UnsupportedOperationException if the remove
* operation is not supported by this Iterator.
* @throws IllegalStateException if the next method has not
* yet been called, or the remove method has already
* been called after the last call to the next
* method.
*/
@Override
public void remove() {
if(lastUserRequest!=null){
doneRequestCodes.remove(lastUserRequest.getRequestCode());
userRequests.remove(lastUserRequest);
lastUserRequest=null;
}
}
/**
* 比较用户请求优先级(优先级高先被响应)
* 比较规则:VIP优先;其次存款优先;其次按请求时间早者优先
* @param userRequest1 用户请求1
* @param userRequest2 用户请求2
* @return 用户请求1优先级高于用于请求2返回1;用户请求1优先级等于用于请求2返回0;用户请求1优先级低于用于请求2返回-1
*/
private int compareUserRequest(UserRequest userRequest1,UserRequest userRequest2){
// vip比较
if(userRequest1.isVip()!=userRequest2.isVip()){
if(userRequest1.isVip()){
return 1;
}else{
return -1;
}
}
// 请求类型比较
if(userRequest1.getType()!=userRequest2.getType()){
if(userRequest1.getType()return 1;
}else{
return -1;
}
}
// 日期比较
return userRequest2.getRequestDate().compareTo(userRequest1.getRequestDate());
}
}
上述代码中,20行,上一个请求对象lastUserRequest 用于实现93行接口方法remove。24行,已遍历请求代码集合doneRequestCodes防止请求被重复访问。借助于doneRequestCodes,53行实现next接口方法时,我们实际上在内部遍历了全部的元素(59行),这样就能够支持集合在遍历过程中的动态变化。108行比较用户请求优先级方法compareUserRequest实现了排序算法。
4.5 UserRequestMgmt
UserRequestMgmt是用户请求管理类,用于管理用户请求。对应于迭代器模式的参与者,UserRequestMgmt是客户Client。下面的代码给出了UserRequestMgmt的声明。
package demo.designpattern.iterator;
import java.util.Iterator;
import java.util.List;
/**
* 用户请求管理器
* Created by LiMingzi on 2017/8/8.
*/
public class UserRequestMgmt {
/**
* 用户请求集合
*/
private UserRequestList userRequests;
/**
* 用户请求迭代器
*/
private Iterator userRequestIterator;
/**
* 构造方法
*/
public UserRequestMgmt() {
this.userRequests = new UserRequestList();
this.userRequestIterator=userRequests.iterator();
}
/**
* 获取用户请求
* @return 用户请求
*/
public UserRequest getRequest(){
// 用户请求
UserRequest userRequest=null;
if(userRequestIterator.hasNext()){
userRequest=(UserRequest)userRequestIterator.next();
userRequestIterator.remove();
}
return userRequest;
}
/**
* 加入请求
* @param userRequest 用户请求
*/
public void putRequest(UserRequest userRequest){
userRequests.add(userRequest);
}
}
上述代码中,14行与18行分别声明了成员变量userRequests和userRequestIterator用来表示用户请求集合及其迭代器,它们均在构造方法中初始化。31行,getRequest方法,通过调用迭代器的next方法(35行)获取一个需要处理的请求,并将其从集合中移除(36行)。45行,加入请求方法putRequest通过调用用户请求集合的add方法(46行)实现用户请求的添加。
4.6 测试代码
为了测试本文中的代码,我们可以编写如下测试代码。测试代码中依次生成三个用户请求,之后响应一个用户请求,再添加两个用户请求,最后响应所有的用户请求。读者可以从测试代码中看到我们允许动态添加请求,请求的遍历也是按照既定策略执行的。为了使请求时间出现差异,代码中故意在每个请求后加入了1秒的延迟。
/**
* 迭代器测试
*/
public static void iteratorTest() throws InterruptedException {
// 用户请求管理
UserRequestMgmt userRequestMgmt = new UserRequestMgmt();
// 用户请求1
UserRequest userRequest1=new UserRequest("001",false,1);
userRequestMgmt.putRequest(userRequest1);
sleep(1000);
// 用户请求2
UserRequest userRequest2=new UserRequest("002",false,0);
userRequestMgmt.putRequest(userRequest2);
sleep(1000);
// 用户请求3
UserRequest userRequest3=new UserRequest("003",false,0);
userRequestMgmt.putRequest(userRequest3);
sleep(1000);
// 响应一次请求
System.out.println(userRequestMgmt.getRequest());
// 用户请求4
UserRequest userRequest4=new UserRequest("004",true,2);
userRequestMgmt.putRequest(userRequest4);
sleep(1000);
// 用户请求5
UserRequest userRequest5=new UserRequest("005",true,0);
userRequestMgmt.putRequest(userRequest5);
sleep(1000);
// 响应所有剩余请求
while(true){
// 当前请求
UserRequest userRequest = userRequestMgmt.getRequest();
if(userRequest ==null){
break;
}
System.out.println(userRequest);
}
}
编译运行后,得到如下测试结果:
请002号顾客到柜台办理存款业务-Wed Aug 09 00:03:13 CST 2017
请005号VIP顾客到柜台办理存款业务-Wed Aug 09 00:03:16 CST 2017
请004号VIP顾客到柜台办理其他业务-Wed Aug 09 00:03:15 CST 2017
请003号顾客到柜台办理存款业务-Wed Aug 09 00:03:14 CST 2017
请001号顾客到柜台办理取款业务-Wed Aug 09 00:03:12 CST 2017