November 03, 2003

初めての Python - TemplateMethod パターン

[ Python ]

さて、Iterator パターンの次は TemplateMethod です。抽象クラスの AbstractDisplay にいくつかの抽象メソッドを用意しておき、その実装はサブクラスに任せてポリモフィズムを実現してみたいと思います。

抽象クラス AbstractDisplay - abstractdisplay.py

class AbstractDisplay:
    def open (self):
        pass
     
    def show (self):
        pass
    
    def close (self):
        pass
 
    def display (self):
        self.open()
        for i in range(5):
            self.show()
        self.close()
        pass

open(), show(), close() が抽象メソッド(のつもり)。何もしないメソッドです。結城さんの本では、show() ではなく print() なのですが、Python の予約語に被ってしまいエラーになってしまうので、show() に名前を変更しました。

実装クラス(1) CharDisplay - chardisplay.py

from abstractdisplay import AbstractDisplay
import sys
 
class CharDisplay(AbstractDisplay):
    def __init__ (self, ch):
        self.ch = ch
        pass
        
    def open (self):
        print "<<",
        pass
    
    def show(self):
        sys.stdout.write(self.ch)
        pass            
        
    def close (self):
        print ">>"
        pass

AbstractDisplay の実装クラスです。AbstractDisplay を継承し、AbstractDisplay が利用している抽象メソッド(テンプレートメソッド)をそれぞれ実装します。show() のところでは標準出力への書き出しに print ではなく sys.stdout.write() を使っていますが、これは print だと、出力直後に空白が一文字出てしまうためです。

実装クラス(2) StringDisplay - stringdisplay.py

from abstractdisplay import AbstractDisplay
import sys
 
class StringDisplay(AbstractDisplay):
    def __init__ (self, string):
        self.string = string
        self.width = len(string)
        pass
 
    def open(self):
        self.printLine()
        pass
 
    def show(self):
        print "|%s|" % self.string
        pass
 
    def close(self):
        self.printLine()
        pass
 
    def printLine(self):
        sys.stdout.write("+")
        for i in range(self.width):
            sys.stdout.write("-")
        sys.stdout.write("+\n")

別の実装クラス。Python の print は % 演算子と組み合わせると、Perl の printf と同じ働きをするようです。かっこいい。(笑) 文字列クラスは C++ などに同じく、文字のシーケンスになっているので、リストなどと同じようなインタフェースを持っており、長さは len(string) で取得できます。Ruby もそうですが、Perl と違って文字列もオブジェクトとして実装されているというのは、やはり綺麗です。

実行スクリプト - main.py

#!/usr/local/bin/python
from chardisplay import CharDisplay
from stringdisplay import StringDisplay
 
displays = ( CharDisplay('H'), 
             StringDisplay('Hello, World'),
             StringDisplay('Greetings, World') )
 
for d in displays:
    d.display()

() で囲まれたリストのようなデータ型は、書き換え不能なリストのようなもので、タプルと呼ばれる Python 特有のデータ構造です。タプルだと何がいいか、まだよくわかってません。

実行結果

[naoya@mary TemplateMethod]$ python main.py
<<HHHHH>>
+------------+
|Hello, World|
|Hello, World|
|Hello, World|
|Hello, World|
|Hello, World|
+------------+
+----------------+
|Greetings, World|
|Greetings, World|
|Greetings, World|
|Greetings, World|
|Greetings, World|
+----------------+

テンプレートメソッドによるポリモフィズムが実現できました。Python は実行すると、外部モジュールをコンパイルしますが、Perl とは異なり、一度コンパイルされたモジュールはコンパイル済みモジュールとして保存されます。次回以降はこのコンパイル済みモジュールをインポートするので、起動時のオーバーヘッドが軽減されます。今回のスクリプトだと、モジュールを置いたディレクトリに abstractdisplay.pyc, stringdisplay.pyc, chardisplay.pyc といったバイナリファイルができあがりました。モジュールのソースコードを修正した場合、タイムスタンプを比較して、必要なら再コンパイルしてくれる模様。いいですね。

Singleton と FactoryMethod も書いてみましたが、疲れたのでまた後日。

Posted by naoya at November 3, 2003 03:22 AM | トラックバック (0)  b_entry.gif
トラックバック [0件]
TrackBack URL: http://mt.bloghackers.net/mt/suck-tbspams.cgi/597
コメント [1件]

http://www.ruby-lang.org/ja/
は、いかが?

[1] Posted by: 金光雅夫 at November 3, 2003 06:35 AM [返信]