2011-11-23 11 views
6

私はここで働いている1つのアプリケーションでSVGエディタのようなGUIを実装しています。これらは、その上で必要とされるロジックのいくつかの例です:GUIロジックの実装に関するヒント

  • ユーザーがキャンバスの右ボタンでクリックした場合のラインで、新しいノードを作成する必要があり、その後のノードは、「リンク」する必要がありますユーザがノード上の左ボタンをクリックした場合、ポリゴン
  • を形成すること、私は
  • ユーザが
  • 選択されたノードが着色されるべきノードを削除することができ、マウスの位置に応じてポリゴンのセット全体を移動する必要があります異なって
  • ユーザはpressiによって複数のノードを選択することができますSHIFTを押しながらノードをクリックすると

などとなります。

私はすでに、これらの項目のすべてを実装しましたが、私はマウスが& &が動いていない& &左ボタンをクリックした(私は状態を操作するためのフラグを大量に使用しなければならなかった主な理由は、最終結果を言っていませんでした?んこれは)、そして確かにこのコードはよりエレガントになる可能性があります。だから私は少しを調査し、これらのオプションに来ました:

  • パイプラインパターン:私は何だろう/個別論理イベントを処理しまうクラスを作成し、何をすべきかを提供するために、優先順位を使用しますイベントが後続のパイプライン項目にどのように伝播するかを示します。

  • MVC:これは最も一般的な応答ですが、コードをよりきれいにするためにどのように使用できるのかは現時点では非常にぼやけています。

  • ステート・マシン:いいだろうが、ステートマシンの粒度を管理するには、だから私はS.O.を求めている

を複雑になります良いと幸せなコードを構築する方法のヒントについてgurus。

答えて

6

UI入力を特定の操作にマッピングするロジックを専用オブジェクトに分離することをお勧めします。それらをSensorオブジェクトと呼ぶことができます。あなたの実装言語を知らないので、私はこれで一般的になるでしょうが、あなたはその考えを得るべきです。

OperationSensor 
+ OnKeyDown 
+ OnKeyPress 
+ OnKeyUp 
+ OnLeftMouseDown 
+ OnLeftMouseUp 
+ OnNodeSelect 
+ OnNodeDeselect 
+ OnDragStart 
+ OnDragStop 

のは、あなたがすべてのさまざまなUIの入力、UiInputManagerを集約する中央のクラスがあるとしましょう。言語固有のメカニズムを使用してキーボードとマウスの入力を待ち受けます。また、マウスが押されて動かされた場合、つまり論理的に「ドラッグ」していることを検出するなどの基本的な操作を検出します。

UiInputManager 
// event listeners 
+ keyboard_keydownHandler 
+ keyboard_keyupHandler 
+ mouse_leftdownHandler 
+ mouse_rightdownHandler 
// active sensor list, can be added to or removed from 
+ Sensors 

UiInputManagerは、入力の原因となっている操作を知っている責任はありません。言語固有の方法でセンサーに通知するだけです。

foreach sensor in Sensors 
    sensor.OnDragStarted 

や、センサーは、あなたが今持っている何UiInputManager

RaiseEvent DragStarted 

によって発行された論理的なイベントをリッスン場合OperationSensorサブクラスへのルートを入力する配管です。各OperationSensorは、1回の操作に関係するロジックを備えています。操作の基準が満たされたことを検出すると、適切なCommandオブジェクトを作成し、それをバックアップします。

// Ctrl + zooms in, Ctrl - zooms out 
ZoomSensor : OperationSensor 

    override OnKeyDown 
    { 
     if keyDown.Char = '+' && keyDown.IsCtrlDepressed 
     base.IssueCommand(new ZoomCommand(changeZoomBy:=10) 
     elseif keyDown.Char = '-' && keyDown.IsCtrlDepressed 
     base.IssueCommand(new ZoomCommand(changeZoomBy:=-10)         
    } 

コマンドオブジェクトをセンサーからUiInputManagerに渡すことをお勧めします。マネージャはコマンド処理サブシステムにそれらを渡すことができます。これにより、マネージャは、操作が完了したことをSensorに通知し、必要に応じて内部状態をリセットすることができます。

複数ステップ操作は、2つの異なる方法で処理できます。 SensorOperation内にインナーステートマシンを実装することも、「ステップ1」センサーを作成して「ステップ2」センサーを作成してアクティブセンサーリストに追加することもできます。 「ステップ2」が完了すると、「ステップ1」センサーを再追加して自分自身を取り除くことができます。

+0

それで彼は質問に述べたようにパイプラインを使うべきだと言っていますか? – jgauffin

+1

私は新しいことを提案していました。 (私は思うが)彼は、イベントをキャプチャしてファンネルするためにパイプラインを使いたいとしていると述べ、イベントを最後まで扱うまで、後続のイベントハンドラに連鎖することにした。私は、それらを引き起こすイベントではなく、実行されているオペレーションに焦点を当てました。 OPが彼のpipleineのアイデアを明らかにしたら、私はもう少し比較/比較することができた。私は彼がそれを取るのを見るためにOPの返事を楽しみにしています。 – tcarvin

+0

アドバイスと説明のために+1 – jgauffin

2

Martin FowlerはMVCおよび関連パターンでa good writeupを持っています。また、どのように動作させるべきかをUI要素に知らせるために、command patternを見てみることもできます。

+0

ええ、私はすでにアクション実行を実装するためにコマンドパターンを使用しています。私は今、ロジック混乱を修正することに重点を置いています。 – scooterman

0

最近のMVCは、 。非常に簡単に言えば、M(モデル)は状態を含み、V(ビュー)は視覚的要素を示し、C(コントローラ)はマウスクリックなどのインバウンドのユーザアクションを送出する。目指すのは、おそらく発砲するイベントを除いて、モデルがビューを直接気にしないことです。

私はたぶんモデルに「スマート」を入れます。モデルは、ノードが選択されたとき、その隣接ノードがポリゴン、ステートマシンなどを形成することを知る。この設計は、いくつかの利点をもたらす。 UIレンダリングの詳細から独立しています。コア機能を中断することなく、大きなビュー変更を行うことができます。また、単体テストの方がはるかに簡単です。

3

ビット私はこれに共通のパターンは、さまざまなノード間の相互作用の複雑さを別のクラスに移動するメディエーターパターンであることを付け加えたいと思います。メディエーターConnectionCreatorクラス)。 Gammaらのデザインパターンを参照してください。http://ebookbrowse.com/addison-wesley-gamma-helm-johnson-vlissides-design-patterns-elements-of-reusable-object-oriented-pdf-d11349017

関連する問題