想走?可以!先买票--迭代器模式

1.1 乘车买票,不管你是谁!

售票员检查谁没有买票,把车厢里的人都遍历一遍。

1.2 迭代器模式

迭代器模式(Iterator),提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露该对象的内部表示。[DP]

"你想呀,售票员才不管你上来的是人还是物(行李),不管是中国人还是外国人,不管是不是内部员工,甚至哪怕是马上要抓走的小偷,只要是来乘车的乘客,就必须要买票。同样道理,当你需要访问一个聚集对象,而且不管这些对象是什么都需要遍历的时候,你就应该考虑用迭代器模式。 另外,售票员从车头到车尾来售票,也可以从车尾向车头来售票,也就是说,你需要对聚集有多种方式遍历时,可以考虑用迭代器模式。 由于不管乘客是什么,售票员的做法始终是相同的,都是从第一个开始,下一个是谁,是否结束,当前售到哪个人了,这些方法每天他都在做,也就是说,为遍历不同的聚集结构提供如开始、下一个、是否结束、当前哪一项等统一的接口。"

"哈,本来这个模式还是有点意思的,不过现今来看迭代器模式实用价值远不如学习价值大了,Martin Flower甚至在自己的网站上提出撤销此模式。因为现在高级编程语言如C#、Java等本身已经把这个模式做在语言中了。"

"哦,是什么?"

"哈,foreach你熟悉吗?"

"啊,原来是它,没错没错,它就是不需要知道集合对象是什么,就可以遍历所有的对象的循环工具,非常好用。"

"另外还有像Iterator接口也是为迭代器模式而准备的。不管如何,学习一下GoF的迭代器模式的基本结构,还是很有学习价值的。研究历史是为了更好地迎接未来。"

1.3 迭代器实现

迭代器模式(Iterator)结构图

复制代码
package code.chapter20.iterator1;

import java.util.ArrayList;

public class Test {
	
	public static void main(String[] args){

		System.out.println("**********************************************");		
		System.out.println("《大话设计模式》代码样例");
		System.out.println();		

        ConcreteAggregate bus = new ConcreteAggregate();
        bus.add("大鸟");
        bus.add("小菜");
        bus.add("行李");
        bus.add("老外");
        bus.add("公交内部员工");
        bus.add("小偷");

        //正序迭代器
        //Iterator conductor = new ConcreteIterator(bus);
        //倒序迭代器
        Iterator conductor = new ConcreteIteratorDesc(bus);

        conductor.first();
        while (!conductor.isDone()) {
            System.out.println(conductor.currentItem() + ",请买车票!");
            conductor.next();
        }

		System.out.println();
		System.out.println("**********************************************");

	}
}

//聚集抽象类
abstract class Aggregate{
    //创建迭代器
    public abstract Iterator createIterator();
}

//具体聚集类,继承Aggregate
class ConcreteAggregate extends Aggregate{

    //声明一个ArrayList泛型变量,用于存放聚合对象
    private ArrayList<Object> items = new ArrayList<Object>();
    public Iterator createIterator(){
        return new ConcreteIterator(this);
    }

    //返回聚集总个数
    public int getCount(){
        return items.size();
    }

    //增加新对象
    public void add(Object object){
        items.add(object);
    }
    
    //得到指定索引对象
    public Object getCurrentItem(int index){
        return items.get(index);
    }

}

//迭代器抽象类
abstract class Iterator{

    public abstract Object first();         //第一个
    public abstract Object next();          //下一个
    public abstract boolean isDone();       //是否到最后
    public abstract Object currentItem();   //当前对象

}

//具体迭代器类,继承Iterator
class ConcreteIterator extends Iterator{
    private ConcreteAggregate aggregate;
    private int current = 0;

    //初始化时将具体的聚集对象传入
    public ConcreteIterator(ConcreteAggregate aggregate){
        this.aggregate = aggregate;
    }

    //得到第一个对象
    public Object first(){
        return aggregate.getCurrentItem(0);
    }

    //得到下一个对象
    public Object next() {
        Object ret = null;
        current++;
        if (current < aggregate.getCount()) {
            ret = aggregate.getCurrentItem(current);
        }
        return ret;
    }

    //判断当前是否遍历到结尾,到结尾返回true
    public boolean isDone(){
        return current >= aggregate.getCount() ? true : false;
    }

    //返回当前的聚集对象
    public Object currentItem(){
        return aggregate.getCurrentItem(current);
    }
}

//具体迭代器类(倒序),继承Iterator
class ConcreteIteratorDesc extends Iterator{
    private ConcreteAggregate aggregate;
    private int current = 0;

    public ConcreteIteratorDesc(ConcreteAggregate aggregate){
        this.aggregate = aggregate;
        current = aggregate.getCount()-1;
    }

    //第一个对象
    public Object first(){
        return aggregate.getCurrentItem(aggregate.getCount()-1);
    }

    //下一个对象
    public Object next() {
        Object ret = null;
        current--;
        if (current >= 0) {
            ret = aggregate.getCurrentItem(current);
        }
        return ret;
    }

    //判断当前是否遍历到结尾,到结尾返回true
    public boolean isDone(){
        return current <0 ? true : false;
    }

    //返回当前的聚集对象
    public Object currentItem(){
        return aggregate.getCurrentItem(current);
    }
}

Aggregate聚集抽象类:

ConcreteAggregate具体聚集类:继承Aggregate。

Iterator迭代器抽象类:

ConcreteIterator具体迭代器类:继承Iterator。

其实售票员完全可以用更多的方式来遍历乘客,比如从最高的到最矮的、从最小到最老、从最靓丽酷毙到最猥琐龌龊。

1.4 Java的迭代器师兄

"刚才我们也说过,实际使用当中是不需要这么麻烦的,因为Java语言中已经为你准备好了相关接口,你只需去实现就好。"

Java.util.Iterator支持对集合的简单迭代接口。

Java.util.ListIterator支持对集合的任意方向上迭代接口。

"你会发现,这两个接口要比我们刚才写的抽象类Iterator简洁,但可实现的功能却一点不少,这其实也是对GoF的设计改良的结果。"

"其实具体类实现这两个接口的代码也差别不大,是吗?"

"是的,区别不大,另外这两个是可以实现泛型的接口,去查Java的API帮助就可以了。"

"有了这个基础,你再来看你最熟悉的foreach就很简单了。"

"这里用到了foreach而在编译器里做了些什么呢?其实它做的是下面的工作。"

"原来foreach就是实现Iterator来实际循环遍历呀。"

"如果我们想实现刚才的反向遍历。那就用另一个接口实现。"

复制代码
package code.chapter20.iterator2;

import java.util.Iterator;
import java.util.ListIterator;
import java.util.ArrayList;

public class Test {
	
	public static void main(String[] args){

		System.out.println("**********************************************");		
		System.out.println("《大话设计模式》代码样例");
		System.out.println();		

        ArrayList<String> bus = new ArrayList<String>();
        bus.add("大鸟");
        bus.add("小菜");
        bus.add("行李");
        bus.add("老外");
        bus.add("公交内部员工");
        bus.add("小偷");
        
        System.out.println("foreach遍历:");
        for(String item : bus){

            System.out.println(item + ",请买车票!");

        }
        
        System.out.println();
    
        System.out.println("Iterator遍历:");
        Iterator<String> conductor = bus.iterator();
        while (conductor.hasNext()) {
            System.out.println(conductor.next() + ",请买车票!");
        }
        
        System.out.println();
        
        System.out.println("ListIterator逆向遍历:");
        ListIterator<String> conductorDesc = bus.listIterator(bus.size());

        while (conductorDesc.hasPrevious()) {
        
            System.out.println(conductorDesc.previous() + ",请买车票!");
        
        }

		System.out.println();
		System.out.println("**********************************************");

	}
}

public interface Iterator{

    public boolean hasNext();       //如果迭代具有更多元素,则返回true 
    public Object next();           //返回迭代中的下一个元素
    
}

public interface ListIterator{

    public boolean hasNext();       //如果此列表迭代器在向前遍历列表时具有更多元素,则返回true 
    public Object next();           //返回列表中的下一个元素并前进光标位置

    public boolean hasPrevious();   //如果此列表迭代器在反向遍历列表时具有更多元素,则返回true
    public Object previous();       //返回列表中的上一个元素并向后移动光标位置
    
}

"是的,尽管我们不需要显式地引用迭代器,但系统本身还是通过迭代器来实现遍历的。总的来说,**迭代器(Iterator)模式就是分离了集合对象的遍历行为,抽象出一个迭代器类来负责,这样既可以做到不暴露集合的内部结构,又可以让外部代码透明地访问集合内部的数据。**迭代器模式在访问数组、集合、列表等数据时,尤其是数据库数据操作时,是非常广泛的应用,但由于它太普遍了,所以各种高级语言都对它进行了封装,所以反而给人感觉此模式本身不太常用了。"

1.5 迭代高手

"哈哈,看来那个售票员是最了不起的迭代高手,每次有乘客上车他都数数,统计人数,然后再对整车的乘客进行迭代遍历,不放过任何漏网之鱼,啊,应该是逃票之人。"

"隔行如隔山,任何行业都有技巧和经验,需要多思考、多琢磨,才能做到最好的。"

"嗯,编程又何尝不是这样,我相信代码没有最好,只有更好,我要继续努力。"

相关推荐
Java中文社群3 分钟前
服务器被攻击!原因竟然是他?真没想到...
java·后端
Full Stack Developme14 分钟前
java.nio 包详解
java·python·nio
零千叶30 分钟前
【面试】Java JVM 调优面试手册
java·开发语言·jvm
代码充电宝39 分钟前
LeetCode 算法题【简单】290. 单词规律
java·算法·leetcode·职场和发展·哈希表
li37149089044 分钟前
nginx报400bad request 请求头过大异常处理
java·运维·nginx
庸了个白44 分钟前
一种面向 AIoT 定制化场景的服务架构设计方案
mqtt·设计模式·系统架构·aiot·物联网平台·动态配置·解耦设计
摇滚侠1 小时前
Spring Boot 项目, idea 控制台日志设置彩色
java·spring boot·intellij-idea
Aevget1 小时前
「Java EE开发指南」用MyEclipse开发的EJB开发工具(二)
java·ide·java-ee·eclipse·myeclipse
黄昏晓x2 小时前
C++----多态
java·jvm·c++
Brookty2 小时前
【算法】前缀和
java·学习·算法·前缀和·动态规划