您的位置:首页 > 编程语言 > Java开发

Java设计模式之从[魔兽争霸、星际争霸、DOTA编队]分析迭代器(Iterator)模式

2014-04-15 20:40 603 查看
在即时战略游戏、DOTA中,我们可以多选我们部队,让他们组成一个队伍。在星际1、魔兽3中,一支队伍的最大单位数量为12个,当我们选中一支队伍后,可以命令他们集体朝着哪个方向移动或者进攻,而不用一个一个控制我们的单位。在程序中,我们是如何实现向这支队伍“群发”命令的呢?最开始想到的就是循环——把队伍中的每一个单位加入一个列表中,写一个for循环,依次访问这个列表中的每一个成员,让它们接收命令。

而这一次,我将介绍一下迭代器模式。迭代器对于很多人来说是一个很熟悉的名词,它又叫做游标模式,它可以提供一种顺序访问一个集合对象中每一个元素,而又不暴露此对象的内部表示的方法。简单来说,对于一个集合Team,我们只需要通过next来获取集合中的下一个元素,以及用hasNext来判断是否集合还存在下一个元素,就可以遍历到该Team集合的所有元素了。

在下面这个例子中,假设我有3个英雄单位,分别叫做路西法、卡尔和奈文摩尔,现在我把他们加入了一支队伍,并且遍历输出他们的名字:

import java.util.Arrays;
import java.util.List;

interface Iterator<T>{
T next();
boolean hasNext();
}

class Unit{
private String name;
public Unit(String name){
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}

class Team<T>{
List<T> members ;
int cursor = 0;
public Iterator<T> getIterator(){
return new Iterator<T>(){
public T next(){
T result = members.get(cursor);
cursor ++;
return result;
}
public boolean hasNext(){
return cursor < members.size();
}
};
}

public Team(List<T> members){
this.members = members;
}
}

class IteratorExample
{
public static void main(String[] args) throws InterruptedException {
Unit u1 = new Unit("路西法");
Unit u2 = new Unit("卡尔");
Unit u3 = new Unit("奈文摩尔");
List<Unit> units = Arrays.asList(u1, u2, u3);
Team<Unit> team = new Team<Unit>(units);
Iterator<Unit> iter = team.getIterator(); //获得一个新的迭代器
while (iter.hasNext()){
System.out.println(iter.next().getName());
}
}
}


可以看到,迭代器接口主要定义了两个方法:next()是返回下一个元素,hasNext()返回是否有下一个元素。在Team类中,我们通过getIterator()返回了一个匿名的迭代器,它的内部有一个cursor,其实就是Team类中members列表的游标,每使用迭代器的next(),cursor就会自增1。我们可以在main方法中看到,通过while、hasNext()和next()的配合使用,我们可以遍历到team中的每一个元素,因此程序输出的结果为:

路西法

卡尔

奈文摩尔
下面来解释几个关键的问题:
1、为什么要将Iterator写为内部类?因为我们希望每次使用getIterator返回的都是一个新的迭代器(即每一个迭代器的cursor都是从0开始)。

2、这是否是一个健壮的迭代器?答案:不是。一个健壮的迭代器要求保证插入和删除操作都不会干扰遍历,而在此迭代器中,如果对members进行了添加、删除操作,由于cursor的值不会因此改变,所以会导致遍历被干扰(如在cursor位置之前插入了一个元素,则遍历的时候,会输出两个一模一样的元素)。迭代器在Java、C#中用在foreach语句中最为广泛,且它们不允许在用foreach语句进行迭代器遍历的时候对原集合的对象进行添加、删除元素的操作,因为这样会干扰迭代器。

3、如果想在Java中为一个类实现兼容foreach语句,这个类必须要继承Iterable<T>接口,它会要求这个类必须有一个iterator()方法来返回一个Iterator<T>迭代器。同理,在C#中如果要实现一个类兼容foreach语句,必须要继承IEnumerable<T>接口,它要求此类必须实现GetEnumerator()返回一个IEnumerator迭代器。它们仅仅是名称不同而已,其用途和含义是一样的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: