8月 292008
<< Mercurialリポジトリホスティング || 充電中 >>
現実世界は複雑で主観的なので、正確にモデル化できない。
つまりプログラムの中にモデルとして現実世界の情報を取り込んで、modelの状態に従って処理の手順を分岐させていく方法には無理がある。
そのため、小さくて個別に独立動作するモジュールに分散させて、それぞれのモジュールが環境状態に対応する形で動く様に実装する方が良い。
■モードのあるプログラム
複数のモードがあるシステムを実装するとき、一番簡単な方法はglobal変数に状態名を保存しておく事だ。例えば
String state;
state = “open_mode”;
とか書いておいて、
if(state == “open_mode”){
// 処理
}
else if(state == “wait_mode”){
// 処理
}
のようにする。
こういう方法はprocessingやflashで一番最初に作品を作ったりした場合に多くて、まあ楽なのでこれで良い。
processingだとthreadなどが無いのでdraw()ループ内でstateを判別して回すのが楽というのもある。
ただ、この方法には問題がある。
- stateへのアクセス権限の制限が難しくて、アクセス元が多くなるとバグの元になる
- 複雑なアプリだとstateの種類自体がものすごく増える
ネットがつながっていて、かつログインしていて、かつ〜〜など。人語にするのも面倒なほどのたくさんの条件から、たくさんの内部状態ができる。
■モードが無いプログラム
わりと一番簡単なこの手のシステムの実装方法は、threadやtimerがある環境なら小さいthreadとその連動のためのjob-queueを用意して実装するのが楽な気がする。
ひたすら、
(マイコン内)
1.ボタンの状態を読み続けて、ボタンの状態変化した時に現在時刻とボタンの状態をqueue保存するthread
2.queueを見続けて、何か処理して結果をqueueに保存するthread
3.処理結果を監視し続けて、新しい結果があったらPCにシリアル通信で送り続けるthread
(PC内)
4.シリアルポートを読み続ける
5.なんか処理する
のようにする。この例だと一直線に処理が流れてくるのでまったくqueueを使う必要が無いけど、例えばマイコンで無線の処理も同時にやって、センサ、PC、他のマイコンと3つ又に接続されるように拡張するには、この方法で実装しておいた方が拡張しやすい。queueを監視して処理するthreadをもう一つ足すだけで済むから。
この辺は実装経験の方が専攻していて理論面は最近ちょっと調べた程度なので感覚的なんだけど、
ポイントは、人間の体のように実装する事だと思う。
■隣を見るだけで全体が動くようにする
例えば熱い物を触ったときに頭で考えるよりも速く手をひっこめるように、あるいは階段で足を踏み外しても足が勝手にバランスを整えてしまうように、中央に大きな脳があるのではなく各モジュールに小さい脳があり、それが連動する事で人体を成しているようにプログラムを考える。その手や足の中の脳は体全体や部屋全体を認識しているわけではなくて、皮膚の隣にある熱いコップや、肘ぐらいまでしか認識していない。
このせいでたまにカップ麺を投げて大惨事になったりするけど、最低限
・隣だけ認識する
・環境(外部)からの要因で自動的に動く
ようになっているおかげでなんとか俺は生きている。
グローバル領域にstate変数を置くような実装の場合、自分の中の状態を監視してコードは実行が分岐されるが、
小さなモジュールの中のコードの場合はそうではなく、モジュール自身の中に状態を持たずに環境の状態に応じて処理が分岐される。if条件文で判定される条件式は隣のモジュールへの問いかけになり、帰ってきたメッセージによってコード実行は分岐する
(もちろん実行速度のためにはメッセージの結果はキャッシュしてもいいが)
あと、綺麗にMVCにするには中にmodelを持つわけだけど、XMLのDOMとかと違ってセンサーとか使ってると綺麗にmodelを持つ事自体がすごく難しい事がある。ようはインタフェースからの入力をmodelにするわけだけど、現実世界の現象はそんなに綺麗にmodelになるわけでもないので、むしろ入力に対して適当にレスポンスして、例外的状況をたくさん定義しておく方が良かったりする。
ただし、実験的で何かに特化したプログラミング環境だと、関数をオブジェクトとして扱ったりとか、そういう普通のプログラミング言語として高機能な部分が無くて、こういう実装にはできない事も多い。