Strategyパターン

本記事はGoFのデザインパターンの1つであるStrategyパターンについての解説と実際に実装した記事になります。 ソースコード

適応可能性

  • クライアント内で複数のアルゴリズムを条件分岐で実装している場合
  • アルゴリズムに使うデータをクライアントが知る必要がない場合

解決策

アルゴリズムを実装するクラスをクライアントから切り離して定義しアルゴリズムを変更可能にすること。 これによりアルゴリズムの再利用性も高めることができます。

コード例

簡単にテキストを改行コードに基づいて空行するプログラムを考えます。

Contextクラスは引数にtextを受け取り、改行して表示するクラスです。
またこの際にどのように改行するかをstrategyクラスに任せています。


class Context:

    def __init__(self, strategy):
        self._strategy = strategy

    def print_text(self, text):
        print(self._strategy.next_line(text))

次にStrategyクラスを作ります。

Strategyクラスは単純に改行コード毎に改行させるクラスと、
改行コード1つ起きに改行するクラスの2つを定義します。


class Strategy:

    @abstractmethod
    def next_line(self, text):
        pass


class StrategyA(Strategy):

    def next_line(self, text):
        return text.replace('\n', '\n\n')


class StrategyB(Strategy):

    def next_line(self, text):
        count = 0
        texts = ''
        for s in text:
            if s == '\n':
                count += 1
                if count % 2 == 0:
                    s = '\n\n'
            texts += s
        return texts

Contextの呼び出し元は使いたいStrategyをContextに渡してインスタンス化する必要があります。


if __name__ == '__main__':
    simple_context = Context(StrategyA())
    advance_context = Context(StrategyB())

    text = '''
    こちらはテスト用テキストになります。
    simpleバージョンはは改行コード毎に空行を加え、
    advanceバージョンは偶数の改行コード毎に空行を加えます。
    以上。
    '''

    print('----- simple version -----')
    simple_context.print_text(text)
    print('----- advance version -----')
    advance_context.print_text(text)

# 出力結果
----- simple version -----


    こちらはテスト用テキストになります。

    simpleバージョンはは改行コード毎に空行を加え、

    advanceバージョンは偶数の改行コード毎に空行を加えます。

    以上。


----- advance version -----

    こちらはテスト用テキストになります。

    simpleバージョンはは改行コード毎に空行を加え、
    advanceバージョンは偶数の改行コード毎に空行を加えます。

    以上。

注意点

Strategyクラスのサブクラスに必要なデータをContextクラスが渡す場合に、Strategyのサブクラスによっては余分な引数を受け取る必要が出てきます。

また、Contextクラスを作成する際にContextの呼び出し元がどのStrategyを使うかを一緒に渡す必要が出てきます。