行为型设计模式06-迭代器模式

简介: 行为型设计模式06-迭代器模式

迭代器模式

1、迭代器模式介绍



迭代器模式是一种行为型设计模式,它提供了一种方法来访问聚合对象中的各个元素,而不暴露其内部表示。通过使用迭代器,客户端可以遍历一个聚合对象中的元素,而不必了解其内部实现。


在迭代器模式中,定义了一个迭代器接口,该接口声明了能够访问聚合对象中元素的方法。然后,具体的迭代器实现类实现了这个接口,并提供了一个具体的遍历算法。聚合对象则负责创建并返回其对应的迭代器实例。


例如:在以前坐公交得自己交钱,售票员根据上车的人进行售票,不管什么人都要买票(比如小偷、公交车公司内部人员、程序员等同样要买票人人平等)。售票员其实就是将所有人都遍历了一遍,对每个乘客都要买票。

1.1 迭代器模式基本实现

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


迭代器模式结构图:

Aggregate聚集抽象类:

/**
 * @author Shier
 * CreateTime 2023/5/13 21:07
 * 聚集抽象类
 */
public abstract class Aggregate {
    /**
     * 创建迭代器
     *
     * @return
     */
    public abstract Iterator createIterator();
}


ConcreteAggregate具体聚集类:继承Aggregate。

/**
 * @author Shier
 * CreateTime 2023/5/13 21:09
 * 具体聚集类
 */
public class ConcreteAggregate extends Aggregate {
    /**
     * 存储聚合对象
     */
    private List<Object> list = new ArrayList<>();
    @Override
    public Iterator createIterator() {
        return (Iterator) new ConcreteIterator(this);
    }
    /**
     * 返回聚合总个数
     *
     * @return
     */
    public int getCount() {
        return list.size();
    }
    /**
     * 增加新对象
     *
     * @param obj
     */
    public void add(Object obj) {
        list.add(obj);
    }
    /**
     * 得到指定的对象
     */
    public Object getCurrentItem(int index) {
        return list.get(index);
    }
}

Iterator迭代器抽象类:

/**
 * @author Shier
 * CreateTime 2023/5/13 21:16
 * Iterator 迭代器对象类
 */
public abstract class Iterator {
    // 第一个
    public abstract Object first();
    // 下一个
    public abstract Object netx();
    // 是否到最后
    public abstract boolean isDone();
    // 当前对象
    public abstract Object currentItems();
}


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

/**
 * @author Shier
 * CreateTime 2023/5/13 21:15
 */
public class ConcreteIterator extends Iterator {
    private ConcreteAggregate aggregate;
    public ConcreteIterator(ConcreteAggregate aggregate) {
        this.aggregate = aggregate;
    }
    private int current = 0;
    /**
     * 得到第一个对象
     *
     * @return
     */
    @Override
    public Object first() {
        return aggregate.getCurrentItem(0);
    }
    /**
     * 得到下一个对象
     *
     * @return
     */
    @Override
    public Object netx() {
        Object ret = null;
        current++;
        if (current < aggregate.getCount()) {
            ret = aggregate.getCurrentItem(current);
        }
        return ret;
    }
    /**
     * 判断是否到结尾
     *
     * @return
     */
    @Override
    public boolean isDone() {
        return current >= aggregate.getCount() ? true : false;
    }
    /**
     * 返回当前对象
     *
     * @return
     */
    @Override
    public Object currentItems() {
        return aggregate.getCurrentItem(current);
    }
}


客户端代码:

/**
 * @author Shier
 * CreateTime 2023/5/13 21:27
 */
public class BaseClient {
    public static void main(String[] args) {
        // 聚集对象 上面的例子就相当于公交车bus
        ConcreteAggregate aggregateBus = new ConcreteAggregate();
        aggregateBus.add("shier");
        aggregateBus.add("公交公司员工");
        aggregateBus.add("小菜");
        aggregateBus.add("大白");
        aggregateBus.add("小黑");
        aggregateBus.add("小偷");
        // 迭代器对象声明,即相当于售票员
        ConcreteIterator conductor = new ConcreteIterator(aggregateBus);
        // 向第一个乘客售票
        conductor.first();
        while (!conductor.isDone()) {
            // 没有到最后一个则一直走向下一个乘客
            System.out.println(conductor.currentItems() + ": 请买票!");
            conductor.netx();
        }
    }
}


输出结果:

同时还可以实现倒序:

/**
 * @author Shier
 * CreateTime 2023/5/13 21:15
 * 具体迭代器类 - 倒序
 */
public class ConcreteIteratorDesc extends Iterator {
    private ConcreteAggregate aggregate;
    private int current = 0;
    public ConcreteIteratorDesc(ConcreteAggregate aggregate) {
        this.aggregate = aggregate;
        // 从最后一个开始
        current = aggregate.getCount() - 1;
    }
    /**
     * 得到倒数第一个对象
     *
     * @return
     */
    @Override
    public Object first() {
        return aggregate.getCurrentItem(aggregate.getCount() - 1);
    }
    /**
     * 得到下一个对象
     *
     * @return
     */
    @Override
    public Object netx() {
        Object ret = null;
        // 递减
        current--;
        if (current < aggregate.getCount()) {
            ret = aggregate.getCurrentItem(current);
        }
        return ret;
    }
    /**
     * 判断是否到结尾
     *
     * @return
     */
    @Override
    public boolean isDone() {
        return current >= aggregate.getCount() ? true : false;
    }
    /**
     * 返回当前对象
     *
     * @return
     */
    @Override
    public Object currentItems() {
        return aggregate.getCurrentItem(current);
    }
}


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

2、具体例子说明

2.1 购物车案例


上面也是举例一个坐公交车的列子


下面在用一个例子说明:


假设有一个超市的购物车,其中包含了多种商品,比如苹果、橙子、香蕉等。这个购物车可以看作是一个聚合对象,而其中每种商品则可以看作是购物车中的元素。

如果要遍历购物车中的所有商品,可以使用迭代器模式来实现。首先,定义一个迭代器接口,声明能够访问购物车中商品的方法。比如,可以定义一个Iterator接口,其中包含hasNext()和next()两个方法。


然后,具体的迭代器实现类可以实现这个接口,并提供一个具体的遍历算法。例如,可以定义一个CartIterator类,它维护了购物车的内部状态,并实现了hasNext()和next()方法,通过这两个方法来依次返回购物车中的每个商品。


最后,购物车可以负责创建并返回其对应的迭代器实例。可以定义一个Cart类,其中包含了购物车中所有商品的列表,以及一个getIterator()方法,用于返回一个CartIterator实例。


这样,客户端就可以通过调用getIterator()方法来获取购物车对应的迭代器,并使用它来遍历购物车中的所有商品。这种实现方式让遍历算法与聚合对象分离开来,使代码更加灵活和易于维护。首先,定义迭代器接口 CartIterator

public interface CartIterator {
    boolean hasNext();
    Object next();
}


然后,定义具体的迭代器实现类 CartIteratorImpl

public class CartIteratorImpl implements CartIterator {
    private List<Object> cartList;  // 购物车中的商品列表
    private int position;           // 迭代器当前位置
    public CartIteratorImpl(List<Object> cartList) {
        this.cartList = cartList;
        this.position = 0;
    }
    @Override
    public boolean hasNext() {
        return position < cartList.size();
    }
    @Override
    public Object next() {
        if (!hasNext()) {
            throw new NoSuchElementException();
        }
        Object item = cartList.get(position);
        position++;
        return item;
    }
}


在 CartIteratorImpl 类中,我们使用了一个 List<Object> 来保存购物车中的商品列表,在 hasNext() 和 next() 方法中维护了内部状态 position,以便顺序地遍历购物车中的每个商品。


最后,定义聚合对象 Cart,并在其中实现 getIterator() 方法:

public class Cart {
    private List<Object> itemList;
    public Cart() {
        this.itemList = new ArrayList<>();
    }
    public void addItem(Object item) {
        itemList.add(item);
    }
    public void removeItem(Object item) {
        itemList.remove(item);
    }
    public CartIterator getIterator() {
        return new CartIteratorImpl(itemList);
    }
}


Cart 类中,我们使用了一个 List<Object> 来保存购物车中的商品列表,实现了添加和删除商品的方法。同时,实现了 getIterator() 方法,用于返回购物车对应的迭代器实例 CartIteratorImpl


最后,可以在客户端代码中使用 CartCartIterator 来遍历购物车中的所有商品:

public class Client {
    public static void main(String[] args) {
        Cart cart = new Cart();
        cart.addItem("苹果");
        cart.addItem("橙子");
        cart.addItem("香蕉");
        CartIterator iterator = cart.getIterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
    }
}


输出结果:

苹果
橙子
香蕉


2.2 Java迭代器实现

起始在开发过程中不会向上面那样去搞,因为目前很多开发语言以及接入了这个迭代器模式,比如在Java中以及有了一个Iterator类



2ba5341457efc74a01f3a51bd0e7199d.png


Java 中的 Iterator 类是迭代器模式的一种典型实现。它提供了一种统一的遍历方式,可以对不同类型的集合进行遍历,而无需关心集合内部的实现细节。


在 Java 中,每个实现了 Iterable 接口的对象都可以返回一个 Iterator 对象,用于遍历它所包含的元素。Iterator 接口定义了三个方法:


boolean hasNext():判断集合中是否还有下一个元素;

E next():返回集合中的下一个元素;

void remove():在迭代过程中移除集合中的当前元素,可选操作。

通过调用 hasNext() 和 next() 方法,可以依次访问集合中的每个元素,直到遍历完所有元素为止。在遍历过程中,Iterator 对象负责维护内部状态,以便正确地返回下一个元素。


在迭代器模式中,迭代器对象将遍历算法和集合对象分离开来,避免了暴露集合内部实现细节,并将集合的遍历行为抽象为一个独立的接口。这使得代码更灵活、可扩展、易于维护。


比如,在 Java 中,可以使用 ArrayList、LinkedList、HashSet 等不同类型的集合类,并使用 Iterator 接口来实现对它们的遍历,而无需关心它们内部的实现细节。

3、迭代器模式总结


迭代器模式是一种行为型设计模式,它提供了一种访问集合对象内部元素的方式,而不用暴露集合的内部细节。


在迭代器模式中,集合对象和迭代器对象分别负责实现集合和遍历算法,并相互独立地进行演化和修改。这样可以避免暴露集合内部结构,也方便对集合进行扩展和修改。


迭代器模式主要由四个角色组成:


抽象聚合类(Aggregate):定义集合对象的接口,包括添加、删除元素等方法。

具体聚合类(ConcreteAggregate):实现抽象聚合类接口,存储集合中的元素。

抽象迭代器类(Iterator):定义遍历集合的接口,包括获取下一个元素、判断是否还有下一个元素等方法。

具体迭代器类(ConcreteIterator):实现抽象迭代器接口,负责对集合进行遍历操作。

迭代器模式的优点包括:


将集合对象和遍历算法分离,使得代码更灵活、可扩展、易于维护。

对客户端隐藏集合对象的内部实现,提高了代码的安全性。

支持对同一种数据结构进行不同方式的遍历。

迭代器模式的缺点包括:


需要实现迭代器对象和聚合对象,增加了代码复杂度。

在集合内部元素发生变化时,需要及时更新迭代器状态,否则可能导致遍历结果不正确。

现在很多的开发语言都已经内置了迭代器模式,不要我们自己再去定义组件的迭代器(不能排除有特殊需求,还是得自己定义迭代器)


比如:


在 C# 中,集合类内部实现了 IEnumerable 和 IEnumerator 接口,这两个接口就对应了迭代器模式中的抽象聚合类和抽象迭代器类。同时,C# 也提供了 yield 关键字,方便使用迭代器模式进行集合遍历。

Python 中的 __iter__() 和 __next__() 方法,Ruby 中的 each 方法等

在 Java 中,集合框架中的 Iterator 接口和相应的实现类就是迭代器模式的典型实现。同时,Java 8 还引入了基于 Lambda 表达式的 Stream API,它提供了非常便捷的集合遍历方式,并且可以进行各种数据处理和转换操作,进一步提高了代码的可读性、可维护性和可重用性。

更新迭代器状态,否则可能导致遍历结果不正确。


现在很多的开发语言都已经内置了迭代器模式,不要我们自己再去定义组件的迭代器(不能排除有特殊需求,还是得自己定义迭代器)


比如:


在 C# 中,集合类内部实现了 IEnumerable 和 IEnumerator 接口,这两个接口就对应了迭代器模式中的抽象聚合类和抽象迭代器类。同时,C# 也提供了 yield 关键字,方便使用迭代器模式进行集合遍历。

Python 中的 __iter__() 和 __next__() 方法,Ruby 中的 each 方法等

在 Java 中,集合框架中的 Iterator 接口和相应的实现类就是迭代器模式的典型实现。同时,Java 8 还引入了基于 Lambda 表达式的 Stream API,它提供了非常便捷的集合遍历方式,并且可以进行各种数据处理和转换操作,进一步提高了代码的可读性、可维护性和可重用性。

目录
相关文章
|
1月前
|
设计模式 Java 开发者
Kotlin教程笔记(54) - 改良设计模式 - 迭代器模式
本教程详细讲解Kotlin语法,适合希望深入了解Kotlin的开发者。对于快速学习Kotlin的用户,推荐查看“简洁”系列教程。本文重点介绍迭代器模式,通过具体示例展示了如何在Kotlin中实现迭代器模式,包括使用Iterator、Iterable接口及重载iterator运算符的方法。
32 4
|
1月前
|
设计模式 Java Kotlin
Kotlin学习笔记 - 改良设计模式 - 迭代器模式
Kotlin学习笔记 - 改良设计模式 - 迭代器模式
29 2
|
1月前
|
设计模式 Java 开发者
Kotlin教程笔记(54) - 改良设计模式 - 迭代器模式
本教程详细讲解了Kotlin中的迭代器模式,包括如何通过实现Iterator和Iterable接口以及重载iterator运算符来实现可遍历的自定义集合。示例展示了如何创建一个图书集类,并通过不同方式使其支持遍历操作,适合希望深入了解Kotlin迭代器模式的开发者。
29 3
|
18天前
|
设计模式 Java Kotlin
Kotlin教程笔记(54) - 改良设计模式 - 迭代器模式
Kotlin教程笔记(54) - 改良设计模式 - 迭代器模式
25 0
|
1月前
|
设计模式 Java Kotlin
Kotlin教程笔记(54) - 改良设计模式 - 迭代器模式
Kotlin教程笔记(54) - 改良设计模式 - 迭代器模式
31 1
|
1月前
|
设计模式 Java Kotlin
Kotlin教程笔记(54) - 改良设计模式 - 迭代器模式
Kotlin教程笔记(54) - 改良设计模式 - 迭代器模式
26 1
|
2月前
|
设计模式 安全 Java
Java设计模式-迭代器模式(21)
Java设计模式-迭代器模式(21)
|
4月前
|
存储 NoSQL Go
iLogtail设计模式问题之迭代器模式是如何应用的
iLogtail设计模式问题之迭代器模式是如何应用的
|
5月前
|
设计模式 算法
行为型设计模式之模板模式
行为型设计模式之模板模式
|
4月前
|
设计模式 移动开发 JavaScript
js设计模式【详解】—— 迭代器模式
js设计模式【详解】—— 迭代器模式
30 0