【问题标题】:Solution: Iterator which doesn't know if it has a next element解决方案:不知道是否有下一个元素的迭代器
【发布时间】:2020-07-12 13:40:09
【问题描述】:

我写了一个迭代器,它返回另一个给定无向简单图的固定大小的子图。 它维护一个内部图,该图是当前计算的子图,并具有用于计算下一个子图的私有堆栈和列表。

无法知道迭代器是否可以返回另一个元素,因为算法可能会在尝试查找下一个子图时终止。

在这个设计中,Java 提供的next()hasNext() 模式不起作用。我目前使用以下抽象方法编写了自己的接口 BlindIterator

 /**
 * @return True iff the current element is a valid return.
 */
public boolean hasCurrent();

/**
 * @return Returns the current element, but does NOT generate the next element. This method can be called


 * as often as wanted, without any side-effects.
 */
public T getCurrent();

/**Generates the next element, which can then be retrieved with getCurrent(). This method thus only provides
 * this side-effect. If it is called while the current element is invalid, it may produce and exception,
 * depending on the implementation on the iterator.
 */
public void generateNext();

这是一种常见的模式吗?有比我更好的设计吗?

【问题讨论】:

  • 那么如果#getCurrent 返回当前节点,你将如何进入下一个节点。我认为迭代器在这里可以正常工作,您可以使用 #hasNext 来确定是否存在下一个有效节点,您当前的节点将 always 有效,而 #next 将是一个阻塞/昂贵的调用。然后,您可以围绕#next 优化您的代码,并避免使用#hasNext 生成昂贵的代码
  • 如何安全地开始迭代并获取第一个元素?如果在当前元素无效时调用 generateNext",可能会产生异常"

标签: java oop design-patterns iterator software-design


【解决方案1】:

您实现迭代器以预加载/缓存下一个元素(子图)。

例如,如果您的元素来自Supplier,其中唯一的方法是返回下一个元素的get() 方法,或者null,如果没有更多元素可用,您将实现@987654323 @像这样:

public final class SupplierIterator<E> implements Iterator<E> {

    private final Supplier<E> supplier;
    private E next;

    SupplierIterator(Supplier<E> supplier) {
        this.supplier = supplier;
        this.next = supplier.get(); // cache first (preload)
    }

    @Override
    public boolean hasNext() {
        return (this.next != null);
    }

    @Override
    public E next() {
        if (this.next == null)
            throw new NoSuchElementException();
        E elem = this.next;
        this.next = supplier.get(); // cache next
        return elem;
    }
}

Answer by Joni 有一个很好的Iterator 实现,可以使用你想要的BlindIterator 作为元素的来源。

由于您只是发明了BlindIterator 来解决您对Iterator 的感知限制,因此我建议您不要这样做。让迭代器实现直接调用底层的“生成”逻辑。

【讨论】:

    【解决方案2】:

    我相信你创建的相当于Iterator 接口。这是使用您的BlindIterator 实现Iterator

        class BlindIteratorIterator<T> implements Iterator<T> {
    
            private BlindIterator<T> iterator;
    
            public BlindIteratorIterator(BlindIterator<T> iterator) {
                this.iterator = iterator;
                iterator.generateNext();
            }
    
            @Override
            public boolean hasNext() {
                return iterator.hasCurrent();
            }
    
            @Override
            public T next() {
                T next = iterator.getCurrent();
                iterator.generateNext();
                return next;
            }
        }
    

    【讨论】:

    • next() 必须抛出 NoSuchElementException 如果 hasNext() 将返回 false。该问题没有指定getCurrent() 在没有当前值时会做什么,因此迭代器实现不应依赖于此。例如。 getCurrent() 可以返回null 或抛出IllegalStateException,这两者都对next() 无效。
    • 这个答案解决了我所说的问题,但我意识到我并没有真正捕捉到我正在努力解决的问题。 This 是我的新问题。
    猜你喜欢
    • 2022-01-03
    • 2015-02-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-11
    • 2022-11-18
    • 1970-01-01
    • 2013-07-22
    相关资源
    最近更新 更多