Stateパターンを知れ、ステートマシン記述はわかりやすくなる
参考:
1. Stateパターン - Pythonにおけるデザインパターン -
先日、エンベッデッドスペシャリストの資格を持ち、 ある製品のソフトウェア開発を一人で抱える友人と会う機会があり、 なぜか自分のソースコードを見てもらうことになりました。 そのコードにはステートマシンを使っていて、私はそれなりに納得のいくものになっていたはずでした。
「ハード脳だな」
私はぽかんと口を開け、えっ?という顔をしました。
「お前は並列記述をついついしてしまうハード脳と言ったんだ。」
そういうと彼は語り始めました。
「まず、この部分だが、何かおかしいと思うところはないか?」
注意: 以降のコードは私が作成しました。友人が示したコードをもらおうとしたら、
やらんと言われ手に入れられませんでした、、ですので、書き方は色々まずくごまかしています、、
if (line == []): l = "" elif(state == "NORMAL"): if(line[0]=="`define"): define_list.append(line) l = "" elif(line[0]=="`ifdef"): def_name = [x[1] for x in define_list] if line[1] in def_name: state = "IF_TRUE" else: state = "IF_FALSE" l = "// " + state +" " + str(def_name)
「えーと、そんなに悪いようには」
「笑止。貴様はステートの遷移(state = xxx)と処理実行(l=xxx)が同時に起こると考えている。
ハードウェア記述言語で書くステートマシンそのものだ。」
「ど、どうすればいいんですか?」
「これを見ろ」
obj.change_state(line) obj.init() obj.main() obj.finish()
「これは?」
「一目瞭然だろう。ステートをチェックして、そのステートで初期化、メインを実行するというステートマシンの記載方法だ。 そして、上のコードを書き換えるとこうなる」
class Context: def __init__(self): self.NORMAL = NORMAL (); self.IF_TRUE = IF_TRUE (); self.IF_FALSE = IF_FALSE(); self.state = self.NORMAL self.line = self.line def change_state(self, line): state = self.state.get_state() if (line == []): self.state = self.state elif(state == "NORMAL"): if(line[0]=="`ifdef"): if line[1] in def_name: self.state = self.IF_TRUE else: self.state = self.IF_FALSE def main(self): self.state.main(l) class State(): def chnge_state(self, l): pass def init(self): pass def main(self, l): pass def finish(self): pass class NORMAL(State): def main(self): l = "// " + state +" " + str(def_name) l = "" print(l) class IF_TRUE (State): def main(self): xxxx obj = Context() obj.change_state(l) obj.init() obj.main() obj.finish()
「わかりやすい!しかもステートごとにくっきり分かれてる!」
「そうだ。これがStateパターンだ。このパタンはステートが増えても対応が容易で、記載が明確だ。」
「こ、これがソフトウェア実務経験うん十年の男の力か、、」
「これくらいは常識だ。そして、デザインパターンは他にもいろいろある。俺もまだ数えられるくらいしか取得していない」
「くっ、私もデザインパターンを取得してみせる!!」
多分続く
あとがき?
というわけで、先日感動した話をわかりやすいかなと思って、ほぼ実話の流れを元に記載してみました。 しかし、まだ理解仕切れていないみたいで、ソースコード含め、内容わかりずらいですね、、
以前から作っているプリプロセッサを改良して処理とステート遷移を綺麗に分けれるように頑張ってみます!!