JavaRush /Java 博客 /Random-ZH /迭代器模式

迭代器模式

已在 Random-ZH 群组中发布
今天我们将讨论Java 中的 Iterator 是什么以及为什么需要它。
迭代器模式 - 1
您可能已经知道,Java 有一个出色的 Collection 接口,它实现了 Iterator 接口。让我立即保留意见:迭代器接口不应该与Java中的迭代器模式混淆!为了澄清这一点,我们首先看一下界面。
从字面上看,“迭代器”可以翻译为“蛮力” 。也就是说,它是某个实体,可以迭代集合中的所有元素。此外,它允许您无需深入研究集合的内部结构和排列即可做到这一点。
让我们想象一下 Java 中没有迭代器。在这种情况下,每个人都必须深入到集合的最深处,真正理解什么是 ArrayListLinkedList什么HashSet不同TreeSet

Iterator必须实现的方法

boolean hasNext()— 如果可迭代对象(当前是 Collection)中仍然有值,则该方法将返回true(如果没有更多值)falseE next()— 返回集合(对象)的下一个元素。如果没有更多元素(没有 check ,我们在到达集合末尾时hasNext()调用),该方法将抛出。 - 将删除最后获得的元素。该方法可以抛出: next()NoSuchElementExceptionvoid remove()next()
  • UnsupportedOperationException,如果此迭代器不支持该方法remove()(例如,在只读集合的​​情况下)
  • IllegalStateException,如果该方法next()尚未被调用,或者remove()自上次调用以来已被调用next()
因此,List 的迭代器是最常见的实现。迭代器从集合的开头到结尾:它查看是否存在下一个元素,如果存在则返回它。一个循环就是建立在这个简单算法的基础上的for-each。它的扩展是ListIterator。让我们看看其他的 java 列表迭代器方法。您很可能认识他们:
  • void add(E e)— 插入一个元素E到;List
  • boolean hasPrevious()true— 反向查找时如果List有元素则返回;
  • int nextIndex()— 将返回下一个元素的索引;
  • E previous()— 将返回前一个工作表元素;
  • int previousIndex()— 将返回前一个元素的索引;
  • void set(E e)- 将替换上次调用返回的元素next()previous()的元素e
让我们看一个小例子。让我们创建一个List包含对学生的问候语的行:
List<String> list = new ArrayList<>();
list.add("Hello");
list.add("Обучающимся");
list.add("На");
list.add("JavaRush");
现在我们将获得它的迭代器并将所有包含的行打印到控制台:
Iterator iterator = list.iterator();
while (iterator.hasNext()) {
    System.out.println(iterator.next());
}
现在就会出现一个“瓶颈”:Java Collections,正如您可能知道的那样(如果您不知道,请弄清楚),扩展接口,Iterable但这并不意味着仅支持迭代器。For也受支持,但必须调用 for : ListSetQueuejava Map iteratorMap.entrySet()
Map<String, Integer> map = new HashMap<>();
Iterator mapIterator = map.entrySet().iterator();
然后该方法next() 将返回一个Entry包含“键”-“值”对的对象。那么一切都与以下相同List
while (mapIterator.hasNext()) {
    Map.Entry<String, Integer> entry = mapIterator.next();
    System.out.println("Key: " + entry.getKey());
    System.out.println("Value: " + entry.getValue());
}
你想:“停下来。我们正在谈论界面,文章的标题说“模式”。也就是说,迭代器模式就是Iterator接口?或者界面是一种模式吗?如果这个词第一次出现,我给你一个参考:模式是一种设计模式,是一个类或许多互连的类必须遵守的某种行为。java中的迭代器可以为任何内部结构涉及迭代的对象实现,并且您可以更改正在讨论的方法的签名。实现模式时最重要的是类必须遵守的逻辑。 迭代器接口是同名模式的私有实现,List, Set, Queue, Map由程序员自行决定应用于现成的结构 ( ) 和其他结构。通过扩展 Iterator 接口,您可以实现一个模式,但不需要扩展该接口来实现该模式。一个简单的比喻:所有的鱼都会游泳,但并不是所有会游泳的都是鱼。作为一个例子,我决定采用……这个词。更具体地说,是一个名词。它由几个部分组成:前缀、词根、后缀和词尾。对于单词的一部分,我们将创建一个接口WordPart和扩展它的类Prefix, Root, Suffix и Ending::
interface WordPart {
    String getWordPart();
}

static class Root implements WordPart {

    private String part;

    public Root(String part) {
        this.part = part;
    }

    @Override
    public String getWordPart() {
        return part;
    }
}

static class Prefix implements WordPart {

    private String part;

    public Prefix(String part) {
        this.part = part;
    }

    @Override
    public String getWordPart() {
        return part;
    }
}

static class Suffix implements WordPart {

    private String part;

    public Suffix(String part) {
        this.part = part;
    }

    @Override
    public String getWordPart() {
        return part;
    }
}

static class Ending implements WordPart {

    private String part;

    public Ending(String part) {
        this.part = part;
    }

    @Override
    public String getWordPart() {
        return part;
    }
}
然后类Word(单词)将包含部分,除了它们之外,我们还将添加一个反映单词中部分数量的整数:
public class Word {

    private Root root;
    private Prefix prefix;
    private Suffix suffix;
    private Ending ending;
    private int partCount;

    public Word(Root root, Prefix prefix, Suffix suffix, Ending ending) {
        this.root = root;
        this.prefix = prefix;
        this.suffix = suffix;
        this.ending = ending;
        this.partCount = 4;
    }

    public Word(Root root, Prefix prefix, Suffix suffix) {
        this.root = root;
        this.prefix = prefix;
        this.suffix = suffix;
        this.partCount = 3;

    }

    public Word(Root root, Prefix prefix) {
        this.root = root;
        this.prefix = prefix;
        this.partCount = 2;
    }

    public Word(Root root) {
        this.root = root;
        this.partCount = 1;
    }

    public Root getRoot() {
        return root;
    }

    public Prefix getPrefix() {
        return prefix;
    }

    public Suffix getSuffix() {
        return suffix;
    }

    public Ending getEnding() {
        return ending;
    }

    public int getPartCount() {
        return partCount;
    }

    public boolean hasRoot() {
        return this.root != null;
    }

    public boolean hasPrefix() {
        return this.prefix != null;
    }

    public boolean hasSuffix() {
        return this.suffix != null;
    }

    public boolean hasEnding() {
        return this.ending != null;
    }
好的,我们有四个重载的构造函数(为简单起见,我们假设我们只能有一个后缀)。名词不能由一个前缀组成,因此对于具有一个参数的构造函数,我们将设置根。现在让我们编写一个迭代器模式的实现:WordIterator,重写 2 个方法:hasNext()next()
public class WordIterator implements Iterator<Word.WordPart> {

    private Word word;
    private int wordPartsCount;

    public WordIterator(Word word) {
        this.word = word;
        this.wordPartsCount = word.getPartCount();
    }

    @Override
    public boolean hasNext() {
        if (wordPartsCount == 4) {
            return word.hasPrefix() || word.hasRoot() || word.hasSuffix() || word.hasEnding();
        } else if (wordPartsCount == 3) {
            return word.hasPrefix() || word.hasRoot() || word.hasSuffix();
        } else if (wordPartsCount == 2) {
            return word.hasPrefix() || word.hasRoot();
        } else if (wordPartsCount == 1) {
            return word.hasRoot();
        }
        return false;
    }

    @Override
    public Word.WordPart next() throws NoSuchElementException {
        if (wordPartsCount <= 0) {
            throw new NoSuchElementException("No more elements in this word!");
        }

        try {
            if (wordPartsCount == 4) {
                return word.getEnding();
            }
            if (wordPartsCount == 3) {
                return word.getSuffix();
            }
            if (wordPartsCount == 2) {
                return word.getPrefix();
            }
            return word.getRoot();
        } finally {
            wordPartsCount--;
        }
    }
}
剩下的就是将迭代器分配给类Word
public class Word implements Iterable<Word.WordPart> {@Override
	public Iterator<WordPart>iterator() {
    		return new WordIterator(this);
	}}
现在我们对“rush”一词进行语素分析:
public class Main {
    public static void main(String[] args) {
        Word.Root root = new Word.Root("беж");
        Word.Prefix prefix = new Word.Prefix("пере");
        Word.Suffix suffix = new Word.Suffix("к");
        Word.Ending ending = new Word.Ending("a");

        Word word = new Word(root, prefix, suffix, ending);

        Iterator wordIterator = word.iterator();
        while (wordIterator.hasNext()) {
            Word.WordPart part = (Word.WordPart) wordIterator.next();
            System.out.println(part.getClass() + ": " + part.getWordPart());
        }
    }
}
请注意,在迭代器模式的实现中,我选择了以下输出顺序:
  1. 结尾
  2. 后缀
  3. 安慰
在设计自己的迭代器时,您可以根据需要指定迭代算法。祝你学习顺利!
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION