■
import sys class Screen: def outputToStdout(self, s): sys.stdout.write(s) class Printer: def output(self, *args): raise NotImplementedError class PrinterScreenAdapter(Printer): def __init__(self, screen): self.__screen = screen def output(self, s): self.__screen.outputToStdout(s) if __name__ == '__main__': screen = Screen() adapter = PrinterScreenAdapter(screen) adapter.output("Test success")
This is basic of Adapter pattern.
I have an idea for Meta programming that generate
adapter class from adaptee and interface table(maybe dictionary)
from types import StringType, ClassType, DictType def generate_adapter(adapter_name, adaptee, interfaces): """ """ if type(adapter_name) != StringType: raise TypeError if type(adaptee) != ClassType: raise TypeError if type(interfaces) != DictTye: raise TypeError # create a class object (meta class) adapter = type(adapter_name, (), {}) # set constructor def __init__(self): self.__adaptee = adaptee() adapter.__init__ = __init__ # set new APIs for i in interfaces.keys(): if hasattr(adaptee, i): def __method(self, *args): getattr(self.__adaptee, i. *args) setattr(adapter, interfaces[i], __method) else: raise NotImplementedError return adapter if __name__ == '__main__': adapter = 'PrinterScreenAdapter' old_api = Screen new_api = { 'outputToStdout':'output' } NewScreen = generate_adapter(adapter, old_api, new_api) screen = NewScreen() screen.output("Test success")
Screenクラスの outputToStdout メソッドを呼ぶ
output メソッドを持つクラスを動的に生成している。
API 変換のデーブルを定義するだけで、簡単にアダプターを作れる。
欠点は、拡張性かな。メソッドを橋渡しする際に、
ちょっとした処理を加えたい場合等には対応出来ない。
でも、単純なAPIの変換には役立つはず。
クラス・ファクトリーを考える前は、
クラスのメソッド自体をリネームしようとしたのだけど、
メソッド内で同じクラスのメソッドを呼んでいたりすると NameError
と、シンボル名が解決出来なくなるので無理だった。(予想通りだけど)
Screenクラスを直接操作する方法では、名前が重複しない場合という前提で。
単純に、メソッドに別名を与えて新しい API としてもいいかな。
Screen.output = Screen.outputToStdout
汎用的な関数にしてみると・・・
def adapt(adaptee, adapter={}): for i in adapter.keys(): if hasattr(adaptee, i): setattr(adaptee, adapter[i], getattr(adaptee, i)) else: raise NotImplementedError adapt(Screen, {'outputToStdout': 'output'})