まず前回の実装と実行結果。それぞれラベルをクリックすると開きます。
#!/usr/bin/env python # -*- coding: utf-8 -*- class Interpreter: def __init__(self, context): self.cn = context def interpret(self): status = SIni() for s in self.cn: print "=======================================" status.setCurrent(s) status = status.interpret() return status class State: SONE=1 STWO=2 STHREE=3 OWN=-1 #status=[S1,S2,S3] #status={SONE:S1, STWO:S2, STHREE:S3} def __init__(self, current=None): if(self.__class__.__name__=="State"): raise Exception,"abstract class \"State\"" self.current = current self.prestate = None def setCurrent(self, s): self.current = s return self def setPrestate(self, pre): self.prestate = pre return self def getStateCode(self): if(self.current == State.SONE): return State.SONE elif(self.current == State.STWO): return State.STWO elif(self.current == State.STHREE): return State.STHREE else: raise Exception, "SyntaxError" def isMatch(self): #s = (self.line) #print "isMatch(): "+str(self.__class__.OWN) if(self.getStateCode()==self.__class__.OWN): #print "T" return True #print "F" return False def delegate(self): #print " DELEGATE *** "+StateFactory.Create(self.getStateCode(), self.current).__class__.__name__ #cstate = self #return StateFactory.Create(self.getStateCode(), self.current).setPrestate(cstate).interpret() s = StateFactory.Create(self.getStateCode(), self.current) s.setPrestate(self) print "DELEGATE: "+s.prestate.tostring() return s.interpret() def interpret(self): if(self.isMatch()): # do approximate processing.... return self else: return self.delegate() i def tolist(self): ret = [self] elm = self while not elm.prestate is None: ret.insert(0,elm.prestate) elm = elm.prestate return ret def __iter__(self): for el in self.tolist(): yield el def tostring(self): return "State"+str(self.__class__.OWN) class SIni(State): OWN=0 def interpret(self): if(not self.isMatch()): return self.delegate() class S1(State): OWN=1 def interpret(self): if(self.isMatch()): print "! STATE(1) printing by "+self.__class__.__name__ print " > pre: "+self.prestate.__class__.__name__ return self else: return self.delegate() class S2(State): OWN=2 def interpret(self): if(self.isMatch()): print "# state[2] printing by "+self.__class__.__name__ print " > pre: "+self.prestate.__class__.__name__ return self else: return self.delegate() class S3(State): OWN=3 def interpret(self): if(self.isMatch()): print "% sTaTe{3} printing by "+self.__class__.__name__ print " > pre: "+self.prestate.__class__.__name__ return self else: return self.delegate() class StateFactory: status={State.SONE:S1, State.STWO:S2, State.STHREE:S3} @classmethod def Create(cls, scode, current): return StateFactory.status[scode](current) def test(): lis = [1,2,3,2,3] intp = Interpreter(context=lis) result = intp.interpret() print result.prestate print "\n" #for elm in result.tolist(): for elm in result: print elm.__class__.__name__ #while not result.prestate is None: # print result.tostring() # result = result.prestate if __name__=="__main__": test()
======================================= DELEGATE: State0 ! STATE(1) printing by S1 > pre: SIni ======================================= DELEGATE: State1 # state[2] printing by S2 > pre: S1 ======================================= DELEGATE: State2 % sTaTe{3} printing by S3 > pre: S2 ======================================= DELEGATE: State3 # state[2] printing by S2 > pre: S3 ======================================= DELEGATE: State2 % sTaTe{3} printing by S3 > pre: S2 <__main__.S2 instance at 0x7f0a44f36b90> SIni S1 S2 S3 S2 S3
各Stateは「行」が表す情報の「大分類」に相当します。Stateパターンもどきを適用していることで、サブクラス内ではそのクラスが表す「大分類」の内側、内部的な状態遷移に専念させることができます。
なんとなくですが、どうなの?と思ってる部分がいくつかかあって、
最後のに関して言えば、生のテキストが入ったファイルオブジェクトの参照を保持し、簡単のため除去しているメタ情報の類とか消費時間とかの情報の削除もこのクラス(もしくは内部で持ってるオブジェクト)の責任とすべきか?というようなことになります。インタプリタクラスの責任ってどこまでなのか?クライアントや他のクラスで責任を受け持つべきことって何なのか?というような部分になります。
現状の自分の答えとしては、おそらくInterpreterはファイルを渡して結果を返すまで、つまり最初から最後までの責任を持ち、クライアントにあたる側からはその詳細はある程度隠蔽されているべき。で、「結果を返すまで」だと責任が大きすぎるから、内部では委譲を活用しながらこまごました責任を分担していく。という形が良いのかなと。フォーマット、もしくはバージョン、または実装のバージョンアップに対応するためには、分担するオブジェクトたちの生成や構造の設計についてはAbstractFactory, Builder, Bridge, Decorator, Strategyあたりが必要となってきそうです。あとはComposite, Facadeとかでしょうか。もちろん全部が全部適用可能なわけではないし、必要以上のデザインパターンの使用はかえってコードを理解しづらくし、保守を難しくさせるとも言います。そのあたりはあまり調子に乗らず、デザインパターン至上主義に陥らないよう気をつけたい所ですけどね。とりあえず、このプロトタイプはもっと良いものになる余地があると思うので、もうちょい考察しながら第2弾を作っていきたいです。
今回久々にjQueryに触りました。だいぶ忘れてたからちょっとは復習できてよかった。