Template Methodパターン
結城浩さんの「Java言語で学ぶデザインパターン入門」を題材にpythonでデザインパターンを
書いてみる。
今回はTemplate Methodパターン。
どんなものかというと、スーパークラスにテンプレートとなるメソッドが定義される。
ただその定義の中ではメソッドは実装されない。
メソッドを実装するのはサブクラスで、そこで具体的な処理が決まるというもの。
異なるサブクラスが異なる実装をすれば、異なる処理が行われけど、処理の大きな流れはスーパークラスで
決めたとおりになる。
このように、スーパークラスで処理の大きな枠組みを決めておいて、サブクラスでその具体的処理を決める
デザインパターン。
サンプルになっているのは、文字や文字列を5回繰り返して表示するもの(template.py)。
まずはAbstractDisplayクラス
class AbstractDisplay(object): def opening(self): pass def printing(self): pass def closing(self): pass def display(self): self.opening() #openingメソッドの呼び出し for i in range(5): #printingメソッドを5回呼び出し self.printing() self.closing() #closingメソッドを呼び出し
ここでは「opening」、「printing」、「closing」の3つのメソッドを宣言して、
displayメソッドの中でその具体的な処理が決まっていない3つのメソッドを使っていて、
displayメソッドがテンプレートメソッドになる。
opening,printing,closingメソッドを実装するのはサブクラスが担う。
次はCharDisplayクラス
class CharDisplay(AbstractDisplay): def __init__(self, ch): self.ch = ch def opening(self): print "<<", def printing(self): print self.ch, def closing(self): print ">>"
ここではAbstractDisplayクラスを継承してopening,printing,closingメソッドを実装している。
つづいてStringDisplayクラス
class StringDisplay(AbstractDisplay): def __init__(self, st): self.st = st self.width = len(self.st) #文字列の長さを出しておく def opening(self): self.printLine() #このクラスのメソッドprintLineで線を引く def printing(self): print "|%s|" %(self.st) #文字列の前後に"|"を付ける def closing(self): self.printLine() #このクラスのメソッドprintLineで線を引く def printLine(self): #printLineメソッドを実装 print "+", #枠の角の"+"を表示 n = 0 while n < self.width: #文字列の長さの分の"-"を表示 print "-", n += 1 print "+" #枠の角の"+"を表示
ここでもAbstractDisplayクラスを継承してopening,printing,closingメソッドを実装している。
最後にCharDisplayクラスとStringDisplayクラスのインスタンスを作ってdisplayメソッドを呼ぶ。
d1 = CharDisplay("H") d2 = StringDisplay("Hello, world.") d1.display() d2.display()
d1,d2はAbstractDisplayクラスのサブクラスのインスタンスだから継承したdisplayメソッドが使える。
さて、実行してみると、
C:\works\python\book1>python template.py << H H H H H >> + - - - - - - - - - - - - - + |Hello, world.| |Hello, world.| |Hello, world.| |Hello, world.| |Hello, world.| + - - - - - - - - - - - - - +
あれ?文字の間にスペースができてしまってる。
どうやらprintを使うと出力直後に空白が一文字出てしまうためみたい。
そこで標準出力への書き出しに print ではなく sys.stdout.write() を使って書き直し。他にも短く書けるところを修正してみた。
修正CharDisplayクラス
import sys class CharDisplay(AbstractDisplay): def __init__(self, ch): self.ch = ch def opening(self): print "<<", def printing(self): sys.stdout.write(self.ch) def closing(self): print ">>"
修正StringDisplayクラス
class StringDisplay(AbstractDisplay): def __init__(self, st): self.st = st self.width = len(self.st) def opening(self): self.printLine() def printing(self): print "|%s|" %(self.st) def closing(self): self.printLine() def printLine(self): sys.stdout.write("".join(("+","-"*self.width,"+\n")))
それでは実行してみると、
C:\works\python\book1>python template.py <<HHHHH>> +-------------+ |Hello, world.| |Hello, world.| |Hello, world.| |Hello, world.| |Hello, world.| +-------------+
きれいに収まった。
同じメソッドを使っているけど実際の動作は個々のクラスのCharDisplayとStringDisplay
で決まっているわけだ。