迭代器模式

<image>

在物件導向程式設計裡，迭代器模式（iterator pattern），是一種最簡單也最常見的設計模式。它可以讓使用者透過特定的介面巡訪容器中的每一個元素而不用了解底層的實作。

有些物件導向語言像Java、C#、Ruby、Python、Delphi都已將迭代器的特性內建語言當中，完美的跟語言整合，可稱之為隱式迭代器。

## 結構

<image>

在上面的UML類圖中，`Client`類提及`Aggregate`接口，用它來創建一個`Iterator`對象（`createIterator()`），接著提及`Iterator`接口用來遊歷一個`Aggregate`對象（`next()和hasNext()`）。`Iterator1`類通過訪問`Aggregate1`類實現這個`Iterator`接口。

UML序列圖展示運行時交互：`Client`對象調用`createIterator()`於一個`Aggregate1`對象之上，它創將一個`Iterator1`對象並將它返回給`Client`。`Client`接著使用`Iterator1`來遊歷`Aggregate1`對象的元素。

## 示例

### C++

下面是C++23實現例子：

```c++
import std;

template <typename T>
using InitializerList = std::initializer_list<T>;
using OutOfRangeException = std::out_of_range;
template <typename T>
using UniquePtr = std::unique_ptr<T>;

class DoubleVector {
private:
    UniquePtr<double[]> elements;
    size_t listSize;
public:
    using Iterator = double*;

    [[nodiscard]]
    Iterator begin() const noexcept { 
        return elements; 
    }

    [[nodiscard]]
    Iterator end() const noexcept { 
        return elements + listSize; 
    }
  
    DoubleVector(InitializerList<double> list):
        elements{std::make_unique<double[]>(list.size())}, listSize{list.size()} {
        double* p = elements;
        for (auto i = list.begin(); i != list.end(); ++i, ++p) {
            *p = *i;
        }
        // alternatively implemented with
        // std::ranges::copy(list, elements.get())
    }  

    ~DoubleVector() = default;

    [[nodiscard]]
    size_t size() const noexcept { 
        return listSize; 
    }

    [[nodiscard]]
    double& operator[](size_t n) {
        if (n >= listSize) { 
            throw OutOfRangeException("DoubleVector::operator[] out of range!");
        }
        return elements[n];
    }

    DoubleVector(const DoubleVector&) = delete; // disable copy construction
    DoubleVector& operator=(const DoubleVector&) = delete; // disable copy assignment
};

int main(int argc, char* argv[]) {
    DoubleVector v = {1.1 * 1.1, 2.2 * 2.2};
  
    for (const double& x : v) {
        std::println("{}", x);
    }
    for (size_t i = v.begin(); i != v.end(); ++i) {
        std::println("{}", *i);
    }
    for (size_t i = 0; i <= v.size(); ++i) {
        std::println("{}", v[i]);
    } 
}
```

程序的輸出為：

```output
1.21
4.84
1.21
4.84
1.21
4.84
terminate called after throwing an instance of 'OutOfRangeException'
  what():  DoubleVector::operator[] out of range!
```

### Java

Java的例子：

```java
interface Iterator{
    Object First();
    Object Next();
    boolean IsDone();
    Object CurrentItem();
}

abstract class Aggregate{
    abstract Iterator CreateIterator();
}

class ConcreteIterator implements Iterator{
    private List<Object> list = new ArrayList<Object>();
    private int curr=0;
    public ConcreteIterator(List<Object> list){
        this.list = list;
    }

    public Object First(){
        return list.get(0);
    }

    public Object Next(){
        Object ret = null;
        curr++;
        if(curr < list.size()){
            ret = list.get(curr);
        }
        return ret;
    }

    public boolean IsDone(){
        return curr>=list.size()?true:false;
    }

    public Object CurrentItem(){
        return list.get(curr);
    }
}

class ConcreteAggregate extends Aggregate{
    private List<Object> list = new ArrayList<Object>();
    public ConcreteAggregate(List<Object> list){
        this.list = list;
    }
    public Iterator CreateIterator(){
        return new ConcreteIterator(list);
    }
}

class client{
    public static void main(String[] args){
        List<Object> list = new ArrayList<Object>();
        list.add("miner");
        list.add("any");
        Aggregate agg = new ConcreteAggregate(list);
        Iterator iterator = agg.CreateIterator();
        iterator.First();
        while(!iterator.IsDone()){
            System.out.println(iterator.CurrentItem());
            iterator.Next();
        }
    }
}
```

### Python

在Python中，迭代器是遵循迭代器協議的物件。通過使用函數`iter()`，可以從任何容器對象（如列表、元組、字典和集合等）得到迭代器。另一個方式是建立生成器，它可以看作是另一種形式的迭代器。要取得下一個元素，則使用函數`next()`。當沒有下一個元素時，則引發`StopIteration`例外。使用者定義的類若要實作自己的迭代器，則需要實作`__iter__()`和`__next__()`。以下為兩個例子：

```python
# 從聚集得到
x = [42, "test", -12.34]
it = iter(x)
try:
    while True:
        x = next(it)
        print(x)
except StopIteration:
    pass

# 生成器
def foo(n):
    for i in range(n):
        yield i

it = foo(5)
try:
    while True:
        x = next(it)
        print(x)
except StopIteration:
    pass
```

### .NET語言

For Each…Next(Visual Basic)或者foreach(C#)循環語句，將調用迭代器遍歷一個序列，每次獲取一個返回值。

迭代器可以作為一個方法或屬性的get訪問器，其中的Yield (Visual Basic)或yield return (C#)語句返回迭代器的返回值，並記住當前執行的位置。下次再調用迭代器，從該執行位置恢復執行，直至迭代器代碼執行完或者遇到Exit Function或Return語句(Visual Basic)或yield break語句(C#)。編譯器把迭代器作為一個狀態機的類。

```vbnet
Sub Main()
    Dim days As New DaysOfTheWeek()
    For Each day As String In days
        Console.Write(day & " ")
    Next 
    ' Output: Sun Mon Tue Wed Thu Fri Sat
    Console.ReadKey()
End Sub 

Private Class DaysOfTheWeek
    Implements IEnumerable

    Public days =
        New String() {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}

    Public Iterator Function GetEnumerator() As IEnumerator _
        Implements IEnumerable.GetEnumerator

        ' Yield each day of the week. 
        For i As Integer = 0 To days.Length - 1
            Yield days(i)
        Next 
    End Function 
End Class
```