週末!プログラミング部

ソフトウェア開発ネタを中心に自分でいろいろ調べた内容を自分の勝手な解釈で思うがままに書いくためのブログ。サンプルソースコード、API、プラットフォーム、プログラミング言語、開発環境などを調査、分析して追求いく予定です。

Pythonでデザインパターン 参ノ型「TemplateMethod」

今回はPythonの勉強しながらデザインパターンTemplateMethodをやってみました。
他のパターンにつきましては、以下の目次記事をご参照ください。

TemplateMethodとは

直訳すると「型板手続き」みたいな意味になります。
wikiには「ある処理のおおまかなアルゴリズムをあらかじめ決めておいて、そのアルゴリズムの具体的な設計をサブクラスに任せること」とあります。

TemplateMethodについて考えてみる

TemplateMethodパターンは抽象クラスを使用することで実現することができます。
いつもどおり、ざっくりした例で説明してみます。

以下はテンプレートクラス:Templateです。
このクラスではinterfaceA()、interfaceB()、interfaceC()というインタフェースがあります。
また、methodA()というメソッドがあり、このメソッドではinterfaceA()、interfaceB()、interfaceC()を順番に呼び出しています。 これがテンプレートメソッドとなります。

class Template(metaclass=ABCMeta) :

    @abstractmethod
    def _interfaceA(self) :
        pass

    @abstractmethod
    def _interfaceB(self) :
        pass

    @abstractmethod
    def _interfaceC(self) :
        pass

    def methodA(self) :
        self._interfaceA()
        self._interfaceB()
        self._interfaceC()

そして以下がTemplateクラスを継承した実体クラス:Hogeです。
このクラスではTemplateクラスのinterfaceA()、interfaceB()、interfaceC()をオーバライドして実装しています。 処理内容は割愛で(;^ω^)

class Hoge(Template) :

    def _interfaceA(self) :
        # 処理A

    def _interfaceB(self) :
        # 処理B

    def _interfaceC(self) :
        # 処理C

最後にHogeクラスを使用するmainの例です。
この例ではHogeクラスのインスタンスを作成して、methodA()を呼び出しています。

if __name__ == '__main__' :
    hogo = Hogo()
    hogo.methodA() # interfaceA, B, Cが順番に呼び出される

HogeクラスはTemplateクラスを継承しているので、TemplateクラスのmethodA()が呼び出されます。
したがってHogeクラスで実装したinterfaceA()、interfaceB()、interfaceC()が順番に呼び出されます。

この例をwikiの言葉を借りてまとめると、
methodA()のように、「ある処理のおおまかなアルゴリズムをあらかじめ決めておいて」、
interfaceA()、interfaceB()、interfaceC()のように、別クラスで実装することで「そのアルゴリズムの具体的な設計をサブクラスに任せる」
という感じがTemplateMethodパターンとなります(・`ω´・)

サンプルプログラム

以下、サンプルプログラムです。
AbstractDisplayクラスがテンプレートクラス、displey()がテンプレートメソッドになります。
そしてCharDisplayとStringDisplayクラスがAbstractDisplayクラスを継承した実体クラスです。
CharDisplayは1文字、StringDisplayは文字列をdispley()で指定したように表示するようになっています。
そのために、それぞれAbstractDisplayクラスのインタフェースであるmyOpen()、myPrint()、myClose()をオーバライドして実装しています。
CharDisplayクラスのmyOpen()、myClose()は"***"、myPrint()ではコンストラクタで指定された文字を表示するようになっています。
またStringDisplayクラスではmyClose()は"---"、myPrint()ではコンストラクタで指定された文字列を表示するようになっています。

# coding: utf-8

from abc import ABC, ABCMeta, abstractmethod

class AbstractDisplay(metaclass=ABCMeta) :

    @abstractmethod
    def myOpen(self) :
        pass

    @abstractmethod
    def myPrint(self) :
        pass

    @abstractmethod
    def myClose(self) :
        pass

    def displey(self) :
        self.myOpen()
        for i in range(3) :
            self.myPrint()
        self.myClose()

class CharDisplay(AbstractDisplay) :

    def __init__(self, ch) :
        self.__ch = ch

    def myOpen(self) :
        print("***")

    def myPrint(self) :
        print(self.__ch)

    def myClose(self) :
        print("***")

class StringDisplay(AbstractDisplay) :
    
    def __init__(self, str) :
        self.__str = str
    
    def myOpen(self) :
        print("---")

    def myPrint(self) :
        print(self.__str)

    def myClose(self) :
        print("---")

if __name__ == '__main__' :

    cd = CharDisplay('T')
    sd = StringDisplay("Design Pattern")
    sd2 = StringDisplay("Template Method")

    cd.displey()
    sd.displey()
    sd2.displey()

実行結果は以下になります!
CharDisplayのdispley()とStringDisplayで表示結果は異なるけれど(myOpen()、myPrint()、myClose()の実装は異なるけれど)、アルゴリズムは同じ(displey()でmyOpen()、myPrint()、myClose()を使用する手順は同じ)であるとわかります(・`ω´・)v

$ python TemplateMethod.py
***
T
T
T
***
---
Design Pattern
Design Pattern
Design Pattern
---
---
Template Method
Template Method
Template Method
---