Pythonで学ぶデザインパターン入門 Template Methodパターン
結城先生の Java言語で学ぶデザインパターン入門
のコードを Python に書き直していくシリーズ第3段です。
Template Method パターンとは
文字通り、処理の大枠のテンプレートを作るパターンです。
具体的には、抽象クラスなどで処理のテンプレートを作成し、その詳細な実装は継承したクラスに任せるといったものになります。
ソースコード
コードの概要
「文字や文字列を5回繰り返して表示する」プログラムです。
抽象クラスである AbstractDisplay
に display
メソッドが定義されており、それを叶えるために3つのメソッドが定義されています。
そのメソッドの中身は何も定義されておらず、その処理をサブクラスに任せるといったものになります。
つまり、その処理次第で多種多様な display
メソッドが構築できるといったことになります。
ソースコード
AbstractDisplay(処理のテンプレートが記載してある抽象クラス)
# coding: utf-8 from abc import ABCMeta, abstractmethod class AbstractDisplay(metaclass=ABCMeta): @abstractmethod def open(self): pass @abstractmethod def print(self): pass @abstractmethod def close(self): pass def display(self): self.open() for i in range(5): self.print() self.close()
概要通りのコードですね。
display
メソッドだけが具体的に記載されています。
それ以外のメソッドをサブクラスで実装しましょう。
CharDisplay(文字単体をdisplayする)
# coding: utf-8 from template_method.abstract_display import AbstractDisplay class CharDisplay(AbstractDisplay): def __init__(self, ch: str): if len(ch) > 1: raise TypeError('文字は一文字') self.__ch = ch def open(self): print('<<', end='') def print(self): print(self.__ch, end='') def close(self): print('>>')
H
を入力としたら <<HHHHH>>
といった出力があることを期待するものとなります。
抽象クラスのものを素朴に継承してるだけですね。
Pythonのprintは勝手に改行されてしまうので、改行しないようには一工夫必要です。
StringDisplay(文字列をdisplayする)
# coding: utf-8 from template_method.abstract_display import AbstractDisplay class StringDisplay(AbstractDisplay): def __init__(self, string: str): self.__string = string self.__width = len(string.encode('utf-8')) def open(self): self.print_line() def print(self): print('|%s|' % self.__string) def close(self): self.print_line() def print_line(self): print('+', end='') for i in range(self.__width): print('-', end='') print('+')
Hello World.
を入力とすると
+------------+ |Hello World.| |Hello World.| |Hello World.| |Hello World.| |Hello World.| +------------+
を期待するものです。
ここまでいじくってても、 open
close
print
の3メソッドがあれば成り立ちます。
実行ファイル
# coding: utf-8 from template_method.char_display import CharDisplay from template_method.string_display import StringDisplay if __name__ == '__main__': d1 = CharDisplay('H') d2 = StringDisplay('Hello World.') d3 = StringDisplay('こんにちわ。') d1.display() d2.display() d3.display()
実際どう便利か
このパターンは簡単ですが、便利な図を想像しづらいかもしれません。
例えば、このソースコードのパターンで画像で同じ出力が欲しくなった時に上記の通りに実装するといった方針が立てられます。
その上で同じスーパークラスを継承してるので、型の制限もしやすいといったメリットもあります。
紹介したソースコードは簡単なロジックでしたが、もっと複雑になってくるとロジックがテンプレートとして用意されていることは可読性に非常に効いてくるので、とても便利ですよ。