まず前回の実装と実行結果。それぞれラベルをクリックすると開きます。
#!/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に触りました。だいぶ忘れてたからちょっとは復習できてよかった。