GoFのデザインパターンを学習する素材として、書籍「増補改訂版Java言語で学ぶデザインパターン入門」が参考になるみたいですね。ただ、取り上げられている実例は、JAVAベースのため、自分の理解を深めるためにも、Pythonで同等のプラクティスに挑んでみました。
■ Template Method(テンプレート・メソッド・パターン)
Template Methodパターン(テンプレート・メソッド・パターン)とは、GoF(Gang of Four; 4人のギャングたち)によって定義されたデザインパターンの1つである。「振る舞いに関するパターン」に属する。Template Methodパターンの目的は、ある処理のおおまかなアルゴリズムをあらかじめ決めておいて、そのアルゴリズムの具体的な設計をサブクラスに任せることである。そのため、システムのフレームワークを構築するための手段としてよく活用される。
UML class diagram
■ "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
クラスが、この役を努めます。
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
クラスが、この役を努めます。
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
メソッドが、この役を努めます。
from templatemethod.display import CharDisplay, StringDisplay
def startMain():
d1 = CharDisplay('H')
d2 = StringDisplay("Hello, World!")
d1.display()
print("")
d2.display()
if __name__ == '__main__':
startMain()