31 设计模式:迭代器模式-行为型模式

98 阅读6分钟

行为型模式之:

  • 观察者模式(Observer) ✅ 重要程度:⭐️⭐️⭐️⭐️⭐️

  • 迭代器模式(Iterator) ✅ 重要程度:⭐️⭐️⭐️⭐️⭐️

  • 职责链模式(Chain of Responsibility)
    重要程度:⭐️⭐️⭐️

  • 命令模式(Command)
    重要程度:⭐️⭐️⭐️⭐️

  • 解释器模式(Interpreter)
    重要程度:⭐️

  • 中介者模式(Mediator)
    重要程度:⭐️⭐️

  • 备忘录模式(Memento)
    重要程度:⭐️⭐️

  • 状态模式(State)
    重要程度:⭐️⭐️⭐️

  • 策略模式(Strategy)
    重要程度:⭐️⭐️⭐️⭐️

  • 模板方法模式(Template Method)
    重要程度:⭐️⭐️⭐️

  • 访问者模式(Visitor)
    重要程度:⭐️

上一节学习了观察者模式,并且横向扩展了应用场景,针对于EventBus,有一些优化场景没有进一步研究,这一节我们了解下什么是迭代器模式。

1.什么是迭代器模式

迭代器模式是一种行为设计模式,用于提供一种方法来顺序访问聚合对象中的各个元素,而不暴露其内部表示。它将遍历聚合对象的过程封装在一个迭代器对象中,客户端可以通过迭代器对象逐个访问聚合对象的元素,而无需了解其内部结构。 通俗点说,迭代器模式更像遍历工具类,用来遍历遍历集合对象。像list和arraylist具有不同的结构,那么迭代器的构造就是不同的。这样理解应该是没有问题的吧?Google了一下,大概是下面的样子

image.png

细分一下应该是一种数据结构对应一种迭代器

image.png

2.迭代器模式的实现

// 定义聚合接口
interface Aggregate {
    Iterator createIterator();
}

// 定义具体聚合类
class ConcreteAggregate implements Aggregate {
    private String[] elements;

    public ConcreteAggregate(String[] elements) {
        this.elements = elements;
    }

    @Override
    public Iterator createIterator() {
        return new ConcreteIterator(elements);
    }
}

// 定义迭代器接口
interface Iterator {
    boolean hasNext();
    Object next();
}

// 定义具体迭代器类
class ConcreteIterator implements Iterator {
    private String[] elements;
    private int position;

    public ConcreteIterator(String[] elements) {
        this.elements = elements;
        this.position = 0;
    }

    @Override
    public boolean hasNext() {
        return position < elements.length;
    }

    @Override
    public Object next() {
        if (hasNext()) {
            return elements[position++];
        }
        return null;
    }
}

// 客户端代码
public class Main {
    public static void main(String[] args) {
        String[] data = {"A", "B", "C", "D", "E"};
        Aggregate aggregate = new ConcreteAggregate(data);
        Iterator iterator = aggregate.createIterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
    }
}

在这个例子中,Aggregate 定义了一个创建迭代器的接口,ConcreteAggregate 是具体的聚合类,实现了 Aggregate 接口,并创建了具体的迭代器 ConcreteIteratorConcreteIterator 实现了迭代器接口 Iterator,用于遍历 ConcreteAggregate 中的元素。

客户端代码通过聚合对象的 createIterator() 方法获取迭代器对象,然后通过迭代器对象逐个访问聚合对象的元素。这样,客户端代码就不需要了解聚合对象的内部结构,而且可以灵活地遍历聚合对象的元素。

3.迭代器模式的使用场景

  1. 访问聚合对象的元素:当你需要访问一个聚合对象(如列表、集合、数组等)中的元素,但不希望暴露其内部表示时,迭代器模式非常有用。通过迭代器,客户端可以逐个访问聚合对象中的元素,而无需了解其内部结构。
  2. 封装遍历算法:迭代器模式将遍历聚合对象的过程封装在迭代器对象中,客户端无需编写遍历算法,只需使用迭代器提供的方法即可遍历元素。
  3. 支持多种遍历方式:迭代器模式允许聚合对象提供多种迭代方式,例如顺序遍历、倒序遍历、过滤遍历等,客户端可以根据需要选择合适的迭代器来遍历元素。
  4. 解耦客户端和聚合对象:迭代器模式可以将客户端代码与聚合对象的内部结构解耦,客户端只需要通过迭代器访问聚合对象的元素,而无需了解聚合对象的具体实现。

4.迭代器模式的实际使用

许多开源框架和库使用了迭代器模式来处理集合、列表和其他数据结构。以下是一些常见的开源框架和库,它们使用了迭代器模式:

  1. Java标准库中的集合类:Java中的ArrayListLinkedListHashMap等集合类都实现了迭代器模式,使得用户可以通过迭代器遍历集合中的元素。
  2. Android开发中的RecyclerViewRecyclerView是Android开发中常用的列表控件,它使用了迭代器模式来遍历列表中的数据项。通过RecyclerView.Adapter中的ViewHolderonBindViewHolder()方法,可以将数据项绑定到列表项上。
  3. Guava库:Guava是Google开发的一个Java工具库,其中的ListsSetsMaps等工具类提供了丰富的集合操作方法,并使用了迭代器模式来遍历集合中的元素。
  4. Apache Commons库:Apache Commons是Apache软件基金会提供的一个通用的Java工具库,其中的CollectionUtilsIteratorUtils等工具类使用了迭代器模式来对集合进行操作和遍历。
  5. Spring框架:Spring框架中的许多模块都使用了迭代器模式,例如Spring Core模块中的ListableBeanFactory接口和BeanDefinition接口,它们通过迭代器来遍历Spring容器中的Bean定义。

5.优缺点

优点:

  1. 分离了集合对象的遍历行为:迭代器模式将集合对象的遍历行为封装到迭代器中,使得集合对象和遍历算法彼此独立,可以独立地改变它们而不会相互影响。
  2. 简化了集合类接口:使用迭代器模式后,集合类不再需要暴露自己的内部结构,只需提供一个迭代器接口,使得集合类的设计更加简洁和灵活。
  3. 支持多种遍历方式:迭代器模式可以为同一个集合类提供多种不同的遍历方式,而且用户可以根据需要选择不同的迭代器来遍历集合,提高了灵活性和可复用性。
  4. 增强了扩展性:通过定义不同类型的迭代器,可以实现对不同类型集合的遍历,而且可以方便地扩展和增加新的迭代器类型。

缺点:

  1. 增加了系统的复杂性:引入迭代器模式会增加系统中的类和对象数量,增加了系统的复杂性和理解难度。
  2. 对于某些集合类型效率较低:在某些特定的集合类型中,如链表等,使用迭代器模式可能会导致遍历效率较低,因为每次迭代都需要进行对象的访问和方法调用。

6.怎么在迭代器中删除或者增加元素呢?

对于增加和删除元素的机制,一般情况下,如果在遍历过程中对集合进行了增加或删除操作,可能会影响到迭代器的行为和遍历结果。为了避免这种情况下的并发修改异常,可以采取以下两种常见的机制:

  1. 快照机制:在迭代器开始遍历之前,先创建集合的一个快照(副本),然后对快照进行遍历操作,这样即使原集合发生了变化,也不会影响遍历结果(快照机制也可以参照数据的结构)。
  2. 异常机制:如果在迭代过程中发现集合发生了变化,可以抛出一个并发修改异常,通知用户集合发生了改变,遍历可能会产生不确定的结果,一般是和数据库保持数据一致性一样,通过记录修改的次数,或者时间戳