[読書記録]Iteratorパターン

# Chap1 Iterator Pattern
## 目的
- デザインパターンを学ぶために「Java言語で学ぶデザインパターン入門」を読んでいる
- 読んだだけでは頭に入らないため、プライベートで利用しているpython言語で各デザインパターンを実装して理解を深める

## Iterator Patternとは
- for文で使われるループ変数(iなど)を抽象化し、一般化したデザインパターン
- 配列のように何かがたくさん集まっている時に、順番に指し示していくためのもの

```java:繰り返し処理の例
#javaの場合
for(int i=0; i < arr.length; i++ ){
    System.out.println(arr[i])
}
```
### メリット
- Iterator(繰り返し処理)を利用する側がIteratorの実装に依存せずに逐次処理をできる

## クラス図と説明
![2019-10-14-21-16-58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179132/9a4937cd-a07f-d082-4338-2080ebb5a040.png)

### Iterator
- 反復処理を行う
- 要素を順番にスキャンしていくインタフェース
- has_nextメソッドが次の要素が存在するか確認を行う
- nextメソッドが次の要素を得る

### Aggregate
- Iterator(反復役)を作り出すAPI
- iteratorメソッドが「要素を順番にスキャンしてくれる」役割をもつ
### ConcretteIterator
- Iteratorインタフェースを実装する
- 自分が見ている位置(index)とスキャン対象の情報をもつ
### Concrete Aggregate
- Aggreteインタフェースを実装したクラス
- 具体的なIterator(=ConcreteIterator)を作り出す

## コード実装
- 書籍に準じて、本棚に対する逐次処理を見立てた逐次処理を実装した。
- ConcretaAggregateの役割をもつBookShelf(書庫)は複数のBookオブジェクトを持つように実装し、Bookオブジェクトの情報取り出しはBookクラスが務める

![2019-10-14-21-43-18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179132/d86d55a7-27a7-3b2c-1ea8-309d4a9a71ab.png)

### Aggregateインタフェース
- aggregate: 「集める」「集まる」「集合」の意味
- 抽象メソッドでiteratorメソッドをもつ
  - 集合体に対応するIteratorを１個作成する
- 具象クラスはIteratorメソッドを使ってIteratorインターフェすを実装したクラスのインタフェースを作成する
- pythonで抽象クラスを描く場合はabcモジュールからABCMeta, abstractclassmethodをimportする

```python:Aggregateインタフェース
from abc import ABCMeta, abstractclassmethod

#抽象クラス
class Iterator(metaclass=ABCMeta):
    @abstractclassmethod
    def iterator(self):
        pass
```

### Iteratorインタフェース
- ループ変数の役割をもち数え上げを行う
- has_nextメソッドは次の要素が存在するかチェックする抽象メソッド
- nextメソッドは集合体の要素を１個返す。返す時にループ変数を１つ前に進める

```python:Iteratorインタフェース
class Iterator(metaclass=ABCMeta):
    @abstractclassmethod
    def has_next(self):
        # 戻り値はBoolean
        pass
    @abstractclassmethod
    def next(self):
        # 戻り値はクラスインスタンス
        pass
```
### Bookクラス
- 書庫(BookShelf)に格納する１つのデータ
- pythonでクラスを作成した場合は基本的にpublicになる
- 擬似的にprivate変数を作成するためには__(アンダースコア２つ)をつける

```python:Bookクラス
class Book():
    """
    本を表すクラス
    """
    def __init__(self, name):
        self.__name = name

    def getName(self):
        return self.__name
```

### BookShelfクラス
- Aggregateインターフェースを実装する
- 複数の本(Bookオブジェクト)を保持する

```python:BookShelfクラス
class BookShelf(Aggregate):
    def __init__(self, max_size):
        """
        コンストラクタ

        Parameters
        ----------
        max_size: int
            本棚に保管できる最大の数
        """
        self._last  = 0
        self._books = []
    def get_book_at(self,index):
        """
        引数で受け取った場所に格納されている本を返す
        Parameters
        ----------
        index : int
            本が格納されている場所(index)
        Returns
        -------
        book : Book
            本
        """
        book = self._books[index]
        return book

    def append_book(self,book):
        """
        本棚の最後に本を追加するメソッド
        Parameters
        ----------
        book : Book
            追加する本
        """
        self._books.append(book)
        self._last = self._last+1

    def get_length(self):
        """
        格納されている本の数を取得する関数

        Returns
        -------
        last : 格納されている本の数
        """
        return self._last

    def iterator(self):
        """
        イテレータ
        """
        return BookShelfIterator(self)
```

### BookShelfIteratorクラス
- BookShelfクラスのスキャンを担当する
- Iteratorクラス(インターフェース)を実装し、nextメソッドおよびhas_nextメソッドの具体的な処理を記述する
- indexは現在の位置(本棚のどこの位置を指名しているか)

```python:BookShelfIterator
class BookShelfIterator(Iterator):
    """
    BookShelf(本棚)のスキャンを行うクラス
    """
    def __init__(self, book_shelf):
        self._index    = 0
        self._bookshelf= book_shelf
    
    def has_next(self):
        """
        本棚に本があるか操作を行う
        """
        if(self._index < self._bookshelf.get_length()):
            return True
        else:
            return False
    
    def next(self):
        """
        本棚の本を取り出す
        """
        book        = self._bookshelf.get_book_at(self._index)
        self._index = self._index + 1
        return book
```

## サンプルプログラム(python版)
```python:iterator.py
from abc import ABCMeta, abstractclassmethod

class Aggregate(metaclass=ABCMeta):
    @abstractclassmethod
    def iterator(self):
        pass

class Iterator(metaclass=ABCMeta):
    @abstractclassmethod
    def has_next(self):
        pass
    @abstractclassmethod
    def next(self):
        pass

class BookShelfIterator(Iterator):
    """
    BookShelf(本棚)のスキャンを行うクラス
    """
    def __init__(self, book_shelf):
        self._index    = 0
        self._bookshelf= book_shelf
    
    def has_next(self):
        """
        本棚に本があるか操作を行う
        """
        if(self._index < self._bookshelf.get_length()):
            return True
        else:
            return False
    
    def next(self):
        """
        本棚の本を取り出す
        """
        book        = self._bookshelf.get_book_at(self._index)
        self._index = self._index + 1
        return book
class Book():
    """
    本を表すクラス
    """
    def __init__(self, name):
        self._name = name

    def getName(self):
        return self._name

class BookShelf(Aggregate):
    def __init__(self, max_size):
        """
        コンストラクタ

        Parameters
        ----------
        max_size: int
            本棚に保管できる最大の数
        """
        self._last  = 0
        self._books = []
    def get_book_at(self,index):
        """
        引数で受け取った場所に格納されている本を返す
        Parameters
        ----------
        index : int
            本が格納されている場所(index)
        Returns
        -------
        book : Book
            本
        """
        book = self._books[index]
        return book

    def append_book(self,book):
        """
        本棚の最後に本を追加するメソッド
        Parameters
        ----------
        book : Book
            追加する本
        """
        self._books.append(book)
        self._last = self._last+1

    def get_length(self):
        """
        格納されている本の数を取得する関数

        Returns
        -------
        last : 格納されている本の数
        """
        return self._last

    def iterator(self):
        """
        イテレータ
        """
        return BookShelfIterator(self)

def main():
    # 本棚を作成
    book_shelf = BookShelf(4)
    book_shelf.append_book(Book("Around the world"))
    book_shelf.append_book(Book("Bible"))
    book_shelf.append_book(Book("Cindelella"))
    book_shelf.append_book(Book("Daddy-Long-Legs"))

    #イテレータ作成
    it = book_shelf.iterator()
    while(it.has_next()):
        book = it.next()
        print(book.getName())

if __name__ == "__main__":
    main()
```

## 所感
- listで宣言する場合はそこまで使う場面がないのではと思っている。
- クラスで実装する必要がある場面がありましたらご教示いただけると幸甚です。