首页 > 其他分享 >你内部啥样跟我没关系 - 迭代器模式(Iterator Pattern)

你内部啥样跟我没关系 - 迭代器模式(Iterator Pattern)

时间:2025-01-05 14:06:09浏览次数:3  
标签:Iterator 迭代 Pattern ArrayList public cursor new 啥样 lastRet

迭代器模式(Iterator Pattern)

迭代器模式(Iterator Pattern)

迭代器模式(Iterator Pattern)是一种行为型设计模式,它提供了一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示。通过迭代器模式,客户端可以遍历整个集合,而不需要了解底层数据结构的具体实现细节。这不仅提高了代码的抽象层次,也增强了系统的灵活性和可扩展性。

迭代器模式概述

迭代器模式结构图

在这里插入图片描述

迭代器模式涉及的角色

  1. 迭代器接口(Iterator):声明了用于遍历集合的方法,如 hasNext() 和 next() 等。具体迭代器必须实现这些方法,以提供特定类型的遍历逻辑。
public interface Iterator<T> {
    boolean hasNext();
    T next();
}
  1. 具体迭代器(ConcreteIterator):实现了 Iterator 接口的具体类。
public class ConcreteIterator<T> implements Iterator<T> {
    private final List<T> items;
    private int position = 0;

    public ConcreteIterator(List<T> items) {
        this.items = items;
    }

    @Override
    public boolean hasNext() {
        return position < items.size();
    }

    @Override
    public T next() {
        if (!hasNext()) {
            throw new NoSuchElementException();
        }
        return items.get(position++);
    }
}
  1. 聚合接口(Aggregate):接口或抽象类,声明了一个创建迭代器对象的方法。具体聚合类必须实现这个方法,以返回一个与之对应的迭代器实例。
import java.util.Iterator;

public interface Aggregate<T> {
    Iterator<T> createIterator();
}
  1. 具体聚合(ConcreteAggregate):实现了 Aggregate 接口的具体类。
import java.util.ArrayList;
import java.util.List;

public class ConcreteAggregate<T> implements Aggregate<T> {
    private final List<T> items = new ArrayList<>();

    @Override
    public Iterator<T> createIterator() {
        return new ConcreteIterator<>(items);
    }

    // Methods to manipulate the collection, such as add and remove.
    public void addItem(T item) {
        items.add(item);
    }

    public void removeItem(T item) {
        items.remove(item);
    }
}

talk is cheap, show you my code

迭代器模式是一种常见的设计模式,Java的集合里面很多容器类就实现了迭代器模式。我们展示一下ArrayList中关于迭代器的部分源码

  1. 字段
  • int cursor;:指向下一个要返回的元素的索引。
  • int lastRet = -1;:记录上一次调用next()方法返回的元素索引,用于remove()操作;如果值为-1,则表示还没有调用过next()或者最近的一次next()之后已经调用了remove()。
  • int expectedModCount;:在创建迭代器时保存的ArrayList的修改次数(modCount)。这个值用来检测在迭代过程中是否有其他线程或代码修改了ArrayList。
  1. 构造函数
Itr() {
    this.expectedModCount = ArrayList.this.modCount;
}

构造函数初始化expectedModCount为当前ArrayList的modCount,以确保在迭代期间可以检测到结构化修改。

  1. hasNext() 方法
public boolean hasNext() {
    return this.cursor != ArrayList.this.size;
}

检查是否还有更多元素可以迭代。当cursor小于ArrayList的大小时返回true,否则返回false。

  1. next() 方法
public E next() {
    this.checkForComodification();
    int i = this.cursor;
    if (i >= ArrayList.this.size) {
        throw new NoSuchElementException();
    } else {
        Object[] elementData = ArrayList.this.elementData;
        if (i >= elementData.length) {
            throw new ConcurrentModificationException();
        } else {
            this.cursor = i + 1;
            return elementData[this.lastRet = i];
        }
    }
}
  • 首先调用checkForComodification()来验证自迭代器创建以来列表没有被修改。
  • 检查cursor是否超出了列表大小,如果是则抛出NoSuchElementException。
  • 确保cursor不超过内部数组长度,以防止并发修改异常。
  • 更新cursor和lastRet,并返回当前元素。
  1. remove() 方法
public void remove() {
    if (this.lastRet < 0) {
        throw new IllegalStateException();
    } else {
        this.checkForComodification();

        try {
            ArrayList.this.remove(this.lastRet);
            this.cursor = this.lastRet;
            this.lastRet = -1;
            this.expectedModCount = ArrayList.this.modCount;
        } catch (IndexOutOfBoundsException var2) {
            throw new ConcurrentModificationException();
        }
    }
}
  • 检查lastRet是否有效,即之前是否调用了next()方法且未调用过remove()。
  • 再次调用checkForComodification()确保没有发生并发修改。
  • 尝试从ArrayList中移除由lastRet指示的元素,并更新cursor、lastRet和expectedModCount。
  1. forEachRemaining(Consumer<? super E> action)
public void forEachRemaining(Consumer<? super E> action) {
    Objects.requireNonNull(action);
    int size = ArrayList.this.size;
    int i = this.cursor;
    if (i < size) {
        Object[] es = ArrayList.this.elementData;
        if (i >= es.length) {
            throw new ConcurrentModificationException();
        }

        while(i < size && ArrayList.this.modCount == this.expectedModCount) {
            action.accept(ArrayList.elementAt(es, i));
            ++i;
        }

        this.cursor = i;
        this.lastRet = i - 1;
        this.checkForComodification();
    }
}

这是一个优化过的批量处理剩余元素的方法,使用给定的动作(action)对每个剩余元素执行操作,直到所有元素都被处理完毕或发生并发修改。

  1. checkForComodification 方法
final void checkForComodification() {
    if (ArrayList.this.modCount != this.expectedModCount) {
        throw new ConcurrentModificationException();
    }
}

此方法用于检测ArrayList是否在迭代过程中被修改。如果ArrayList的modCount与创建迭代器时保存的expectedModCount不匹配,则抛出ConcurrentModificationException,表明发生了非法的并发修改。

    private class Itr implements Iterator<E> {
        int cursor;
        int lastRet = -1;
        int expectedModCount;

        Itr() {
            this.expectedModCount = ArrayList.this.modCount;
        }

        public boolean hasNext() {
            return this.cursor != ArrayList.this.size;
        }

        public E next() {
            this.checkForComodification();
            int i = this.cursor;
            if (i >= ArrayList.this.size) {
                throw new NoSuchElementException();
            } else {
                Object[] elementData = ArrayList.this.elementData;
                if (i >= elementData.length) {
                    throw new ConcurrentModificationException();
                } else {
                    this.cursor = i + 1;
                    return elementData[this.lastRet = i];
                }
            }
        }

        public void remove() {
            if (this.lastRet < 0) {
                throw new IllegalStateException();
            } else {
                this.checkForComodification();

                try {
                    ArrayList.this.remove(this.lastRet);
                    this.cursor = this.lastRet;
                    this.lastRet = -1;
                    this.expectedModCount = ArrayList.this.modCount;
                } catch (IndexOutOfBoundsException var2) {
                    throw new ConcurrentModificationException();
                }
            }
        }

        public void forEachRemaining(Consumer<? super E> action) {
            Objects.requireNonNull(action);
            int size = ArrayList.this.size;
            int i = this.cursor;
            if (i < size) {
                Object[] es = ArrayList.this.elementData;
                if (i >= es.length) {
                    throw new ConcurrentModificationException();
                }

                while(i < size && ArrayList.this.modCount == this.expectedModCount) {
                    action.accept(ArrayList.elementAt(es, i));
                    ++i;
                }

                this.cursor = i;
                this.lastRet = i - 1;
                this.checkForComodification();
            }

        }

        final void checkForComodification() {
            if (ArrayList.this.modCount != this.expectedModCount) {
                throw new ConcurrentModificationException();
            }
        }
    }

Itr类实现了Iterator接口,提供了安全地遍历ArrayList的方法,并通过expectedModCount机制来保护迭代过程免受并发修改的影响。同时,它还支持remove()操作,允许在迭代过程中移除元素。这种设计保证了迭代的安全性和一致性,同时也符合Java集合框架的标准行为。

总结

迭代器模式的优点包括:

  1. 支持对集合对象的多种遍历:同一个聚合可以有多个遍历方式,且遍历方式可以独立于聚合对象存在。
  2. 简化了聚合类:将遍历逻辑从聚合类中分离出来,使得聚合类的代码更加简洁。
  3. 提高了代码的可维护性和可扩展性:增加新的聚合类和迭代器类都很方便,无需修改原有代码。

迭代器模式缺点:

  1. 由于迭代器模式将存储数据和遍历数据的职责分离,增加新的聚合类需要对应增加新的迭代器类,类的个数成对增加,这在一定程度上增加了系统的复杂性。
  2. 设计难度大,要考虑系统将来的扩展。JDK内置的迭代器不支持逆向遍历,导致只能再增加一个新的子类ListIterator实现。

迭代器模式适用于以下场景:

  1. 当需要对一个聚合对象进行多种方式遍历时。
  2. 当需要对聚合对象提供多种遍历方式,且希望这些遍历方式可以独立于聚合对象存在时。
  3. 当需要封装一个复杂的数据结构,并希望对外提供统一的遍历接口时。

迭代器模式是一种常见的设计模式,它体现了将数据遍历功能与存储数据的形式相隔离的思想。目前迭代器已经成了操作集合的基本工具,Java的容器类大部分都已经实现了这个迭代器接口。

标签:Iterator,迭代,Pattern,ArrayList,public,cursor,new,啥样,lastRet
From: https://blog.csdn.net/Zongkunxue/article/details/144918463

相关文章

  • CanvasContext.createPattern
    CanvasContext.createPattern(stringimage,stringrepetition)CanvasContext是旧版的接口,新版Canvas2D接口与Web一致从基础库2.9.0开始,本接口停止维护,请使用RenderingContext代替基础库1.9.90开始支持,低版本需做兼容处理。小程序插件:支持相关文档:旧版画......
  • 架构师-设计模式-享元模式(FlyWeight Pattern)
    享元模式这个名词可能不像其他设计模式一样直接见名知义,可能不像代理模式、单例模式那样一眼看到就知道是干什么的。接下来解释一下享元这个词的含义,享为共享的意思,元就是对象的意思。通俗得来讲享元模式就是共享对象的意思,这种模式一般在系统底层优化使用得比较多,比如前面说过......
  • 从家谱的层级结构 - 组合模式(Composite Pattern)
    组合模式(CompositePattern)组合模式(CompositePattern)组合模式概述组合模式涉及的角色talkischeap,showyoumycode总结组合模式(CompositePattern)组合模式(CompositePattern)是一种结构型设计模式,它允许你将对象组合成树形结构来表示“部分-整体”的层次关系。组......
  • Java设计模式 —— 【结构型模式】享元模式(Flyweight Pattern) 详解
    文章目录概述结构案例实现优缺点及使用场景概述享元模式也叫蝇量模式:运用共享技术有效地支持大量细粒度的对象;常用于系统底层开发,解决系统的性能问题。像数据库连接池,里面都是创建好的连接对象,在这些连接对象中有我们需要的则直接拿来用,避免重新创建,如果没有我们......
  • Java中Iterator用法整理
    Java中Iterator用法整理|Id|Title|DateAdded|SourceUrl|PostType|Body|BlogId|Description|DateUpdated|IsMarkdown|EntryName|CreatedTime|IsActive|AutoDesc|AccessPermission||-------------|-------------|-------------|-------------|-......
  • 能省一点是一点 - 享元模式(Flyweight Pattern)
    享元模式(FlyweightPattern)享元模式(FlyweightPattern)享元模式(FlyweightPattern)概述享元模式包含的角色:享元模式应用场景talkischeap,showyoumycode总结享元模式(FlyweightPattern)享元模式(FlyweightPattern)是一种结构型设计模式,它主要用于减少创建大量细粒......
  • python : iterable & iterator
    python:iterable&iterator正文在Python中,可迭代对象(Iterable)和迭代器(Iterator)是两个相关但不同的概念,它们都与遍历元素的能力相关。理解它们的区别非常重要,尤其是在编写Python程序时需要处理迭代时。1.Iterable(可迭代对象)一个对象如果是可迭代的,意味着它可以返回一个......
  • More Effective C++之技术Techniques,Idioms,Patterns_条款25
    MoreEffectiveC++之技术Techniques,Idioms,Patterns条款25:将constructor和non-memberfunction虚化constructor虚化将Non-MemberFunctions的行为虚化    本章描述C++程序员常常遭遇的一些问题的解决办法,这些解法都已获得证明。本书把这样的解法称为techniques......
  • Agentic Design Patterns
    AgenticDesignPatternshttps://www.deeplearning.ai/the-batch/how-agents-can-improve-llm-performance/?ref=dl-staging-website.ghost.io Reflection:TheLLMexaminesitsownworktocomeupwithwaystoimproveit. ToolUse:TheLLMisgiventoolssuch......
  • 7.3 Spliterator
    Spliterator(可分迭代器splitableiterator)是java8中加入的另一个新接口。java8中集合框架的所有集合都实现了spliterator接口。publicinterfaceSpliterator<T>{booleantryAdvance(Consumer<?superT>action);Spliterator<T>trySplit();lo......