未来の私へ送るデザインパターン 2/24 [iterator]

このシリーズは、この内容を忘れた未来のcacaponが読んだときに、
自力でそれを使ったプログラムが自作できることを目的として作られました~

こちらの記事は、以下を主に参考に作成しております♪
残りは、cacaponの記憶の片隅にある情報がソース元になります~

www.techscore.com

iteratorとは?

iteratorは日本語だと「反復子」というそうです…
あんまり聞いたことがないです~

プログラマだとイメージつきやすいのはfor文の i変数ですかね?
繰り返すときにどんどん増えてくアレです~
日常生活だと…分からないなぁ…

参考URLだと、最もイメージしやすいデザインパターンがこれらしいので、
こちらから紹介されていました~

メリットとしては、 配列の中から情報の一覧を取得したり、検索を掛けたりする際、
中の構造に関係なく情報を取得できるそうです~
凄いですね~


例題

フッキー博士は未知の生物の研究者。
ある特徴を持つ生物に対し、「パチモン」と名づけ、
パチモンの生態をまとめた図鑑を作ることにしました。

協力者にお願いしていたパチモンの情報が5つ届いたので、
図鑑に情報を追加することにします。

届いた情報は以下の通りです。

  • 名前:マカフクサ 分類:しょくぶつパチモン
  • 名前:ヒグアナ 分類:イグアナパチモン
  • 名前:ヨロイガメ 分類:カメパチモン
  • 名前:マメッポー 分類:ハトパチモン
  • 名前:ネズット 分類:ネズミパチモン

図鑑に追加した後、
図鑑利用者が追加した情報の一覧を見れるようにしてください。

怒られないかなぁ…大丈夫かなぁ…


itaratorを使わないで作ったプログラム

こんな構成で作りました~ f:id:cacapon:20200207150915p:plain

# main.py

from user import User
from doctorfukkey import DoctorFukkey

DrFukkey = DoctorFukkey()
you = User()

DrFukkey.work()
you.lookpicturebook()
# doctorfukkey.py

from picturebook import PictureBook


class DoctorFukkey():
    def work(self):
        use = PictureBook()

        use.add_pachimon_info('マカフクサ', 'しょくぶつパチモン')
        use.add_pachimon_info('ヒグアナ', 'イグアナパチモン')
        use.add_pachimon_info('ヨロイガメ', 'カメパチモン')
        use.add_pachimon_info('マメッポー', 'ハトパチモン')
        use.add_pachimon_info('ネズット', 'ネズミパチモン')
# user.py
from pprint import pprint
from picturebook import PictureBook


class User():
    def lookpicturebook(self):
        use = PictureBook()
        pprint(use.show_pachimon_info())
# picturebook.py やむを得ずシングルトンを使用しています

class PictureBook():
    _instance = None
    _pachimon_info = {}

    def __new__(cls):
        if cls._instance is None:
            cls._instance = super().__new__(cls)
            cls._pachimon_info = {}

        return cls._instance

    def add_pachimon_info(self, name, classifying):
        PictureBook._pachimon_info[name] = classifying

    def show_pachimon_info(self):
        return PictureBook._pachimon_info


その後…

考えられるのはこんなところでしょうか?

  • 図鑑の登録形式が変わった。(Noの追加とか、体長、体重の追加など)
  • 一覧でなくで特定の条件のものを表示したい
  • キーワードから特定のパチモンを表示できる

…最初にDict型で作ってしまったせいか、あまりiteratorの恩恵がわかりにくいかもです…


itaratorを使って作ったプログラム

f:id:cacapon:20200207234658p:plain

こんな感じにするそうです。
ではやってみましょう~

# main.py

from concreteaggregate import ConcreteAggregate
from concreteiterator import ConcreteIterator

use = ConcreteAggregate()

use.add_pachimon_info('マカフクサ', 'しょくぶつパチモン')
use.add_pachimon_info('ヒグアナ', 'イグアナパチモン')
use.add_pachimon_info('ヨロイガメ', 'カメパチモン')
use.add_pachimon_info('マメッポー', 'ハトパチモン')
use.add_pachimon_info('ネズット', 'ネズミパチモン')


iterator = ConcreteIterator(use)

while(iterator.hasnext()):
    print(iterator.next())

# iterator.py

from abc import ABCMeta, abstractmethod


class Iterator(metaclass=ABCMeta):
    @abstractmethod
    def hasnext(self):
        pass

    @abstractmethod
    def next(self):
        pass
# concreteiterator.py

from iterator import Iterator


class ConcreteIterator(Iterator):
    def __init__(self, concreteAggregate):
        self.__concreteaggregate = concreteAggregate
        self.__last = 0

    def next(self):
        info = self.__concreteaggregate.get_pachimon_info(self.__last)
        self.__last += 1
        return info

    def hasnext(self):
        if self.__last >= len(self.__concreteaggregate.show_pachimon_list()):
            return False
        return True
# aggregate.py

from abc import ABCMeta, abstractmethod

from iterator import Iterator


class Aggregate(metaclass=ABCMeta):
    def __init__(self):
        self.Iterator = Iterator()

    @abstractmethod
    def iterator(self):
        pass
# concreteaggregate.py

from aggregate import Aggregate
from concreteiterator import ConcreteIterator


class ConcreteAggregate(Aggregate):
    def __init__(self):
        self.__pachimon_info = []

    def add_pachimon_info(self, name, classflying):
        self.__pachimon_info.append([name, classflying])

    def get_pachimon_info(self, index):
        return self.__pachimon_info[index]

    def show_pachimon_list(self):
        return self.__pachimon_info

    def iterator(self):
        return ConcreteIterator(ConcreteAggregate())


その後...の対応例

今回は対応例が思いつかなかったので割愛します~