「Undo」をどう設計する?

ドローツールの Undo をどうやって実装するといいんだろう?っていうギモンにリプ頂いたのでまとめ。もっと話広げられれば良かったかもなぁ。
40
くっくっkura 🇯🇵🦀 @PG_kura

ドローツールの Undo, Redo ってどういう設計になってるんだろ。

2011-07-14 17:12:55
くっくっkura 🇯🇵🦀 @PG_kura

@cocoatomo memento でやるなら、現在の状態から元の状態へ戻す操作オブジェクト、もしくはデータ全体のスナップショットを復元するオブジェクトのどちらかを直列化して持っておくようなイメージなんですけど、どっちなのかなぁ、もしくはそれ以外の方法あるのかなぁ、とか。

2011-07-14 17:27:49
tomo🐧@learning @cocoatomo

@PG_kura 差分を持っているんだと思ってます。じゃないと Redo 何していいか分からないですし。

2011-07-14 17:32:41
くっくっkura 🇯🇵🦀 @PG_kura

@cocoatomo 差分にした場合、描画要素同士が互いに参照しあうようなケースではそれらの参照関係の再構築が必要ですよね。(矢印図形が楕円図形の中心を指す、とか。)そーゆーの考えだすと楽しくて帰りたくなるます。

2011-07-14 17:37:27
tomo🐧@learning @cocoatomo

@PG_kura そうですねー。そこは腕の見せ所な気がします。使いやすさを突き詰めて考える作業ですね。帰りますか??www

2011-07-14 17:41:19
pokarim @pokarim

@PG_kura @cocoatomo 照やポインタを生で使わずに、IDをはさむというのはどうでしょうか。さらに参照関係をオブジェクトの外にだしたらすっきりするかも。ほとんどDBですな。適当に言ってますが。

2011-07-14 17:50:57
pokarim @pokarim

@PG_kura @cocoatomo 勘ですが、参照関係の再構築といったあたりからOOPの枠に収まりにくくなっているような気がします。

2011-07-14 17:53:03
くっくっkura 🇯🇵🦀 @PG_kura

@pokarim 以前、その方法を採ってうまくいったことがあります。しかし、ID で参照するとなると参照したり外したり、の手間がワンクッション入るので、もっと型でガチガチにしてみたいなぁって欲が出てきて、何か無いかなあと思うです。(って問題を混同し過ぎな感じはあるんですけどねw)

2011-07-14 17:58:27
pokarim @pokarim

@PG_kura RDBMSで中間テーブル使うと柔軟になるけど面倒になるというのにも似ているかもですね。参照関係はHashMap使ったりすると思いますが、そういった生の参照でない参照関係オブジェクト的なものへのサポートを充実させるべきなんじゃないかなと思ってます。

2011-07-14 18:05:09
みやびあーつ @miyabiarts

自分のソフトウェアだと、オブジェクトの内部状態を変えるようなメンバ関数の中で復元に必要なデータを保持するUndo用オブジェクトを作成し、全てのUndo用オブジェクトを管理するオブジェクトにスタックで追加していくという感じ。

2011-07-14 17:55:54
みやびあーつ @miyabiarts

ただ今の状態だとクラス自体にUndo用のコードを書かないといけないので、機能があまり切り分けられていないように見える。そのため、クラスごとにUndo用のクラスを作ってObserverパターンで切り分けて、メンバ関数経由でUndoを実行すれば良いけど、

2011-07-14 18:01:04
みやびあーつ @miyabiarts

メンバ関数の呼び出しが多くなると、かなりオーバヘッドが発生してしまうので、妥協して今の形になっているところ。

2011-07-14 18:02:28
みやびあーつ @miyabiarts

3Dモデリングツールで、1万頂点を持つモデルを全選択して動かすと、動かすたびにUndo用オブジェクトが 1万個生成される。

2011-07-14 18:08:53
みやびあーつ @miyabiarts

操作したい頂点をリスト化してから実行するとUndo用オブジェクトは1つで済むけど、リスト化して実行しないといけないこと課すため面倒くさくなったり、Undoの単位がメンバ関数単位以上になって、別のところで設計が複雑になってしまう。

2011-07-14 18:16:33
pokarim @pokarim

@PG_kura 離脱了解です。属性が基本で参照関係的なものは直接サポートされてないから、いざ必要になったときに面倒になってしまうのかなと。参照関係が基本になっていれば、(ID->オブジェクト)をかませるのは関数合成みたいなもので済むかなとか妄想してみました。

2011-07-14 18:10:24
pokarim @pokarim

@PG_kura OOPでもメソッドたくさん書けば隠蔽できますが、setter getterたくさん書いて、全体の記述量は減ってないというか下手したら増えてしまう、みたいなことになりかねないですよね。。。

2011-07-14 18:17:34
くっくっkura 🇯🇵🦀 @PG_kura

@pokarim setter, getter による記述量の増加は横に置いておくとして、( ID -> オブジェクト ) をかませるのは必要で、それを関数使ってやるのも良いかと思うんですが、何度もデータプールに対して問い合わせるのもアレだし、一度参照取得できたならそれ使って

2011-07-14 22:49:10
くっくっkura 🇯🇵🦀 @PG_kura

@pokarim ... 型のメリットも最大限活かしたいですし、ってあれこれまさにリアクティブプログラミングの出番!!... とか、考えてましたw

2011-07-14 22:49:56
pokarim @pokarim

@PG_kura インターフェース的には関数として提示されているけど、参照関係の情報がデータプールにあるのか、インスタンスが自分で持っているかの違いを完全に隠蔽したらいいと思うんですよ。

2011-07-14 23:06:52
pokarim @pokarim

@PG_kura undo,redoのようにイベントの履歴が絡んでくる話は、大抵リアクティブプログラミングに持っていけますぜ、旦那!

2011-07-14 23:08:27

■■■■■■■■■■■■■■■■■■■■■■■■■■■
ちなみに、ここで出てくる
"リアクティブプログラミング"っていうのは
コレ。
[[『なぜリアクティブプログラミングは重要か。』
Conceptual Contexture:http://d.hatena.ne.jp/pokarim/20101226]]

以下、トゥギャった後の反応などピックアップ。
■■■■■■■■■■■■■■■■■■■■■■■■■■■