初探设计模式之【迭代器】

初探设计模式之【迭代器】

一、前言

迭代器提供了一种机制来按顺序访问集合中的各元素,而不需要知道集合内部的构造。

迭代器模式最典型的应用就是 jdk 中集合类中,各种集合的迭代器实现,不论是 list, 还是 set ,都有一套一样的迭代器接口,他们的用法都一样,但是这些集合内部的实现却各不相同。

迭代器让我们不用关系集合类内部的实现,就可以实现对其元素的完整访问。

二、实现

我们可以实现一套像集合一样类似的迭代器接口。

先来构建一种场景,比如要设计一个行车记录仪,支持存储 10 天的数据,当超过 10 天了,可以自动覆盖最早的视频,然后我们需要支持使用迭代器,按时间顺序从近到远的访问。这里,我们需要自己实现迭代器功能。

先定义个 Iterator 接口, 主要定义迭代过程关键的方法。

与 JDK 中的迭代器接口十分相似:

public interface Iterator<T> {

    boolean hasNext();

    T next();

}

Iterable接口

/**
 * 这个类相当于标记某个类,具备迭代器的功能
 *
 * @param <T>
 */
public interface Iterable<T> {

    Iterator<T> iterator();
}

然后再看行车记录仪的实现

DriverRecorder

/**
 * 行车记录仪
 * 最多支持 10 条数据,循环覆盖保存数据
 * 内部使用一个数组保存最多10条数据
 * 其迭代方式为倒序迭代
 */
public class DriverRecorder implements Iterable<RecorderItem> {

    private static final int MAX_SIZE = 10;

    private final RecorderItem[] items = new RecorderItem[MAX_SIZE];

    private int index;

    private int size;

    public void add(RecorderItem item) {
        items[index++] = item;
        if (index == MAX_SIZE) {
            index = 0;
        }

        //记录实际存储的数量
        if (size < MAX_SIZE) {
            size++;
        }
    }

    public int size() {
        return size;
    }

    @Override
    public Iterator<RecorderItem> iterator() {
        return new Itr();
    }

    private class Itr implements Iterator<RecorderItem> {
        private int cursor = index;
        private int loopCount = size;

        @Override
        public boolean hasNext() {
            return loopCount > 0;
        }

        @Override
        public RecorderItem next() {
            loopCount--;
            if (--cursor < 0) {
                cursor = MAX_SIZE - 1;
            }
            return items[cursor];
        }
    }
}

再看看一下调用方:

public static void main(String[] args) {
    DriverRecorder recorder = new DriverRecorder();

    RecorderItem item1 = new RecorderItem("10月05日", "青年路");
    RecorderItem item2 = new RecorderItem("10月06日", "北京路");
    RecorderItem item3 = new RecorderItem("10月07日", "朝阳路");
    RecorderItem item4 = new RecorderItem("10月08日", "香港路");
    RecorderItem item5 = new RecorderItem("10月09日", "上海路");
    RecorderItem item6 = new RecorderItem("10月10日", "天津路");
    RecorderItem item7 = new RecorderItem("10月11日", "湖北路");
    RecorderItem item8 = new RecorderItem("10月12日", "湖南路");
    RecorderItem item9 = new RecorderItem("10月13日", "广东路");
    RecorderItem item10 = new RecorderItem("10月14日", "广西路");
    RecorderItem item11 = new RecorderItem("10月15日", "吉利路");
    RecorderItem item12 = new RecorderItem("10月16日", "山西路");

    recorder.add(item1);
    recorder.add(item2);
    recorder.add(item3);
    recorder.add(item4);
    recorder.add(item5);
    recorder.add(item6);
    recorder.add(item7);
    recorder.add(item8);
    recorder.add(item9);
    recorder.add(item10);
    recorder.add(item11);
    recorder.add(item12);

    Iterator<RecorderItem> iterator = recorder.iterator();
    while (iterator.hasNext()) {
        RecorderItem item = iterator.next();
        System.out.println(item.toString());
    }
}

最后看一下打印的日志:

RecorderItem{time=‘10月16日’, event=‘山西路’}
RecorderItem{time=‘10月15日’, event=‘吉利路’}
RecorderItem{time=‘10月14日’, event=‘广西路’}
RecorderItem{time=‘10月13日’, event=‘广东路’}
RecorderItem{time=‘10月12日’, event=‘湖南路’}
RecorderItem{time=‘10月11日’, event=‘湖北路’}
RecorderItem{time=‘10月10日’, event=‘天津路’}
RecorderItem{time=‘10月09日’, event=‘上海路’}
RecorderItem{time=‘10月08日’, event=‘香港路’}
RecorderItem{time=‘10月07日’, event=‘朝阳路’}

如上,我们的功能完美的实现了。外部很轻松的就能通过迭代器来访问自定义集合中的数据。

为了完成对各种集合类的遍历,我们定义了统一的迭代器接口 Iterator , 基于此我们让集合以内部类的方式实现其特有的迭代逻辑,再将自己标记为 Iterator 并返回迭代器实例,以证明自己是具备迭代能力的。具体的集合内部类结构与迭代逻辑对于客户端这个“局外人”是透明的,客户端只需要知道这个集合是可以迭代的,并向集合发起迭代请求以获取迭代器,这样就可以以大家熟知的方式遍历数据了。

三、总结

对于任何类型的集合,要防止内部机制不被暴露或破坏,以及确保用户对每个元素有足够的访问权限,迭代器模式起到了至关重要的作用。迭代器巧妙的利用了内部类的形式与集合类分离,然则“藕断丝连”,迭代器依然对内部元素保有访问权限,如此便促成了集合的完美封装,在此基础上还提供给用户一套标准的迭代器接口,使各种繁杂的遍历方式得以统一。迭代器模式的应用,能再内部事务不受干涉的前提下,保持一定的对外开放。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值