LoginSignup
5

More than 3 years have passed since last update.

Pythonで、デザインパターン「Template Method」を学ぶ

Last updated at Posted at 2020-02-02

GoFのデザインパターンを学習する素材として、書籍「増補改訂版Java言語で学ぶデザインパターン入門」が参考になるみたいですね。ただ、取り上げられている実例は、JAVAベースのため、自分の理解を深めるためにも、Pythonで同等のプラクティスに挑んでみました。

■ Template Method(テンプレート・メソッド・パターン)

Template Methodパターン(テンプレート・メソッド・パターン)とは、GoF(Gang of Four; 4人のギャングたち)によって定義されたデザインパターンの1つである。「振る舞いに関するパターン」に属する。Template Methodパターンの目的は、ある処理のおおまかなアルゴリズムをあらかじめ決めておいて、そのアルゴリズムの具体的な設計をサブクラスに任せることである。そのため、システムのフレームワークを構築するための手段としてよく活用される。

UML class diagram

templatemethod.png
(以上、ウィキペディア(Wikipedia)より引用)

■ "Template Method"のサンプルプログラム

実際に、Template Methodパターンを活用したサンプルプログラムを動かしてみて、次のような動作の様子を確認したいと思います。

  • 文字"H"を、5回連続で表示する。さらに前後では、"<<", ">>"で囲って表示する
  • 文字列"Hello, World!"を5回連続で表示する。さらに、枠線で囲って表示する
$ python Main.py 
<<HHHHH>>

+-------------+
|Hello, World!|
|Hello, World!|
|Hello, World!|
|Hello, World!|
|Hello, World!|
+-------------+

■ サンプルプログラムの詳細

Gitリポジトリにも、同様のコードをアップしています。
https://github.com/ttsubo/study_of_design_pattern/tree/master/TemplateMethod

  • ディレクトリ構成
.
├── Main.py
└── templatemethod
    ├── __init__.py
    └── display.py

(1) AbstractClass(抽象クラス)の役

AbstractClass役は、テンプレートメソッドを実装します。また、テンプレートメソッドで使っている抽象メソッドを宣言します。この抽象メソッドは、サブクラスであるConcreteClass役によって実装されます。
サンプルプログラムでは、AbstractDisplayクラスが、この役を努めます。

templatemethod/display.py
from abc import ABCMeta, abstractmethod

class AbstractDisplay(metaclass=ABCMeta):
    @abstractmethod
    def print(self):
        pass

    @abstractmethod
    def open(self):
        pass

    @abstractmethod
    def close(self):
        pass

    def display(self):
        self.open()
        for _ in range(5):
            self.print()
        self.close()

(2) ConcreteClass(具象クラス)の役

AbstractClass役で定義された抽象クラスを具体的に実装します。ここで実装したメソッドは、AbstractClass役のテンプレートメソッドから呼び出されます。
サンプルプログラムでは、CharDisplayクラスと、StringDisplayクラスが、この役を努めます。

templatemethod/display.py
class CharDisplay(AbstractDisplay):
    def __init__(self, ch):
        self.__ch = ch

    def open(self):
        print('<<', end='')

    def print(self):
        print(self.__ch, end='')

    def close(self):
        print('>>')

class StringDisplay(AbstractDisplay):
    def __init__(self, string):
        self.__string = string
        self.__width = len(string)

    def open(self):
        self.__printLine()

    def print(self):
        print("|{0}|".format(self.__string))

    def close(self):
        self.__printLine()

    def __printLine(self):
        print('+', end='')
        for _ in range(self.__width):
            print('-', end='')
        print('+')

(3) Client(利用者)の役

サンプルプログラムでは、startMainメソッドが、この役を努めます。

Main.py
from templatemethod.display import CharDisplay, StringDisplay

def startMain():
    d1 = CharDisplay('H')
    d2 = StringDisplay("Hello, World!")
    d1.display()
    print("")
    d2.display()

if __name__ == '__main__':
    startMain()

■ 参考URL

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
5