把书读薄 | 《设计模式之美》设计模式与范式(行为型-迭代器模式)(上)

简介: 本文对应设计模式与范式:行为型(65-67),迭代器模式 (Iterator Pattern),又称 游标模式,用于 解耦容器代码和遍历代码。不过,很多编程语言都将迭代器作为一个基础类库,直接提供出来了。日常业务开发,很少自己实现一个迭代器,当然,弄懂原理能帮助我们更好地使用这些工具类~

0x1、定义


原始定义


迭代器提供一种对容器对象中各个元素进行访问的方法,而又不需要暴露该对象的内部细节。


定义很好理解,上构成该模式的四个角色:


  • Iterator (抽象迭代器类) → 定义统一的迭代器方法hasNext()和next(),用于判断当前集合是否还有其他对象及按顺序读取集合中的当前对象;


  • ConcreteIterator (具体迭代器) → 实现抽象迭代器声明的方法,处理具体集合对象中对对象位置的偏移及具体对象数据的传输;


  • Container (抽象容器类) → 抽象及创建迭代器类关联的方法,同时可添加其他集合类需要的方法;


  • ConcreteContainer (具体容器类) → 实现抽象容器类中声明的方法,创建对应具体的迭代器类;


其实就是两类角色:容器迭代器,写个简单示例帮助理解~


0x2、写个简单例子


// 歌曲实体
public class Music {
    private String name;
    private String singer;
    private long createTime;
    public Music(String name, String singer, long createTime) {
        this.name = name;
        this.singer = singer;
        this.createTime = createTime;
    }
    public String getName() { return name; }
    public String getSinger() { return singer; }
    public long getCreateTime() { return createTime; }
    @Override
    public String toString() { 
        return "【" + name + "】- " + singer + " - " + createTime; 
    }
}
// 抽象迭代器
public interface Iterator {
    // 最基本的两个方法
    Music next();
    boolean hasNext();
    // 按需添加
    Music currentItem();
    Music first();
}
// 抽象容器
public interface Container {
    Iterator createIterator();
}
// 具体迭代器
public class ConcreteIterator implements Iterator {
    private Music[] musics;
    private int pos = 0;
    // 待遍历容器通过依赖注入传递到具体迭代器类中
    public ConcreteIterator(Music[] musics) { this.musics = musics; }
    @Override public Music next() { return musics[pos++]; }
    @Override public boolean hasNext() { return pos < musics.length; }
    @Override public Music currentItem() { return musics[pos]; }
    @Override public Music first() { return musics[0]; }
}
// 具体容器
public class ConcreteContainer implements Container {
    private Music[] musics;
    public ConcreteContainer(Music[] musics) { this.musics = musics; }
    @Override public Iterator createIterator() { return new ConcreteIterator(musics); }
}
// 测试用例
public class IteratorTest {
    public static void main(String[] args) {
        Music[] musics = new Music[5];
        musics[0] = new Music("We Sing. We Dance. We Steal Things.", "Jason Mraz", 20080513);
        musics[1] = new Music("Viva La Vida Death And All His Friends", "Coldplay", 20080617);
        musics[2] = new Music("华丽的冒险 ", "陈绮贞", 20050923);
        musics[3] = new Music("范特西 Fantasy", "周杰伦", 20010914);
        musics[4] = new Music("後。青春期的詩 后青春期的诗", "五月天", 20081023);
        Container container = new ConcreteContainer(musics);
        Iterator iterator = container.createIterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.currentItem());
            iterator.next();
        }
    }
}


代码运行结果如下


网络异常,图片无法展示
|


代码非常简单:


  • 具体迭代器实现next()、hasNext()方法;
  • 待遍历容器对象通过依赖注入传递到迭代器中;
  • 容器通过createIterator()方法创建迭代器;


你可能或说过度设计了,上面的遍历操作,自己通过 for循环foreach循环 都可以实现。


的确如此,那为啥还要给容器设计对应的迭代器呢?三个原因:


  • 复杂数据结构(如图、树),有各种复杂的遍历方式(树的前中后序遍历、图的深广度优先遍历等),如果让客户端来实现这些遍历算法,势必会增加开发成本,而且容易出错;
  • ② 把遍历逻辑放容器类里无疑增加了容器类的复杂性,应对复杂性的方法就是 拆分,可把遍历操作拆分到迭代类中;
  • 每个迭代器独享游标信息,创建多个不同迭代器,同时对同一个容器遍历而不互相影响;


在举个例子,现在需要按照歌曲时间升序遍历,只需要实现一个迭代器类:


public class OrderTimeIterator implements Iterator {
    private final Music[] musics;
    private int pos;
    public OrderTimeIterator(Music[] musics) {
        this.musics = new Music[musics.length];
        System.arraycopy(musics, 0, this.musics, 0, musics.length);
        sortByTimeAsc(this.musics, 0, this.musics.length - 1);
        this.pos = 0;
    }
    // 快速排序
    private void sortByTimeAsc(Music[] arr, int low, int high) {
        if(low > high) return;
        int i = low;
        int j = high;
        Music temp;
        Music anchor = arr[low];
        while (i < j) {
            while (arr[j].getCreateTime() >= anchor.getCreateTime() && i < j) {
                j--;
            }
            while (arr[i].getCreateTime() <= anchor.getCreateTime() && i < j) {
                i++;
            }
            if(i < j) {
                temp = arr[j];
                arr[j] = arr[i];
                arr[i] = temp;
            }
        }
        arr[low] = arr[i];
        arr[i] = anchor;
        sortByTimeAsc(arr, low, j -1);
        sortByTimeAsc(arr, j + 1, high);
    }
    ... // 其他实现方法同ConcreteIterator
}


相关文章
|
4月前
|
设计模式 算法 Java
行为型设计模式-策略模式(Strategy Pattern)
行为型设计模式-策略模式(Strategy Pattern)
|
19天前
|
设计模式 算法 Java
[设计模式Java实现附plantuml源码~行为型]定义算法的框架——模板方法模式
[设计模式Java实现附plantuml源码~行为型]定义算法的框架——模板方法模式
|
19天前
|
设计模式 JavaScript Java
[设计模式Java实现附plantuml源码~行为型] 对象状态及其转换——状态模式
[设计模式Java实现附plantuml源码~行为型] 对象状态及其转换——状态模式
|
19天前
|
设计模式 Go
[设计模式 Go实现] 行为型~迭代器模式
[设计模式 Go实现] 行为型~迭代器模式
|
19天前
|
设计模式 Go
[设计模式 Go实现] 行为型~职责链模式
[设计模式 Go实现] 行为型~职责链模式
|
1月前
|
设计模式 Java
小谈设计模式(21)—迭代器模式
小谈设计模式(21)—迭代器模式
|
2月前
|
设计模式 存储 算法
【设计模式】迭代器模式
【设计模式】迭代器模式
|
4月前
|
设计模式 Java 数据挖掘
聊聊Java设计模式-迭代器模式
迭代器(Iterator)模式,也叫做游标(Cursor)模式。我们知道,在Java 容器中,为了提高容器遍历的方便性,我们利用迭代器把遍历逻辑从不同类型的集合类中抽取出来,从而避免向外部暴露集合容器的内部结构。
45 0
聊聊Java设计模式-迭代器模式
|
4月前
|
设计模式 算法 调度
行为型设计模式:模板设计模式/观察者设计模式/策略设计模式/责任链设计模式
行为型设计模式:模板设计模式/观察者设计模式/策略设计模式/责任链设计模式
34 0
|
4月前
|
设计模式 算法 Go
Golang设计模式——07迭代器模式
Golang设计模式——07迭代器模式
30 0