Adapterパターン
『Rubyによるデザインパターン』(ラス・オルセン著 ピアソン・エデュケーション刊)の例をPythonに変換して書いています。
かなりいい加減です。
アダプターというのは、たとえばUSB-PS2変換器の様に、インターフェイスのギャップを埋めるためのものです。
同じように、必要なメソッドが無いなどの不整合があるとき、ギャップを埋めるのが、
Adapterパターンです。
ここではprint文を例にとります。
print文は,
f = open("log.txt", "w") print>>f, "hello world!"
の様に、出力先を変更できますが、実は >>の右に来るものは、
ファイルでなくても構いません。writeメソッドさえあればよいのです。
となるとTkinter.Textに出力したくなるのは自然ですね?
でも、Tkinter.Textにはwriteメソッドがありません・・・。
#encoding:shift-jis from Tkinter import * class TextWithWrite(object): def __init__(self, *a, **kw): self.text = Text(*a, **kw) def write(self, ss): self.text.insert(END, ss) ## def insert(self, *a, **kw): ## return self.text.insert(*a, **kw) ## ## def delete(self, *a, **kw): ## return self.text.delete(*a, **kw) ## ## ・・・ ## ## あーー!面倒くさい!! def __getattr__(self, name): return getattr(self.text, name) root = Tk() text_ww = TextWithWrite(root) text_ww.pack() print >> text_ww, "fizzbuzz" print >> text_ww, "buzz" print >> text_ww, "fizz" text_ww.see(END) root.mainloop()
Textにwriteメソッドを追加し、晴れてprint出来るようになりました。
今回追加したのはwrite1つだけですが、2個以上メソッドを追加するのも同様です。
ところで、TextWithIOはwrite以外はTextと同じですので、
他のメソッドはそのままself.textに委譲しなければいけません。
compare delete get index insert ... 等、数十個を一々書くのは面倒ですね!
そこで、__getattr__を使います。
def __getattr__(self, name): return getattr(self.text, name)
text_ww.see のように、オブジェクトの属性にアクセスしようとしたが、
text_wwオブジェクトがseeを持っていないとき、__getattr__メソッドが呼ばれます。
nameはアクセスしようとした属性の名前(この場合"see")です。
そして、getattr関数でself.textのseeメソッドを取ってきます。
text_wwはcompareもdeleteもgetも・・・も持っていませんので、
text_ww.compare text_ww.delete text_ww.get 等とされる度に、__getattr__が呼ばれるのです。
さて、この後『Rubyによるデザインパターン』では、RubyらしいAdapterの代替法として、
Pythonでも同じ事は、出来ることは出来ますが、それはそれぞれの項で