課題A4 (機能理解)

課題A4では, JHotDrawの図形の選択機能について見ていきます.
具体的には,

「配置された図形がJHotDrawのシステム内部でどのように管理され,図形選択機能の実行によってどのように取り出されて,どのように選択図形として登録されるか?」
を理解することを目指して, 以下のようにトレースデバッガを操作していきます.
ワークスペース内のjhotdraw7が、JHotDrawを構成するプロジェクトです。


前準備

課題A3 (接近過程抽出) の終了直後は下図のような状態になっているはずです.

まずは, ステップバックオーバーを2回押してから, ステップオーバーを1回押してください.
ここで, 変数ビュー上の「呼び出し後」のメソッド名が Iterator.next() であることを確認してください.
それを確認したら, 変数ビュー上で「呼び出し後」を開いて, 戻り値を右クリックしてください.
右クリックするとポップアップメニューが現れるので, 「オブジェクトの追加時点に飛ぶ」を選択してください.

「オブジェクトの追加時点に飛ぶ」を選択すると, selectedFigures に この RectangleFigure クラスのインスタンス (id = 1952912699) が追加された時点である
DefaultDrawingView クラスの addToSelection(Figure) メソッドの780行目にまで現在の実行時点が遡ります.
下図の状態になっていれば前準備は終了です.


機能理解

Figure クラスは図形を表す JHotDraw のクラスです.
また, RectangleFigure クラスは矩形を表す JHotDraw のクラスで, Figure クラスの子孫クラスにあたります.
現在の実行時点の行は、図形を選択するたびに実行されます.

先ほどの前準備にしたがって進めていくと, 下図のように DefaultDrawingView クラスの
addToSelection(Figure) メソッド内の780行目で一時停止している状態になっているはずです.
この状態になっていれば, ここから時間計測を開始してください. 時間計測はできる限り,1分以内の単位での計測をお願いします.

まずは,「実行時点の登録」ビューの追加ボタンをクリックして実行時点の登録を行ってください.
ここで, ソースコードと変数ビューを見ると, DefaultDrawingView クラスのインスタンス (id = 150367587) のフィールド selectedFigures が参照しているセットへは
RectangleFigure クラスのインスタンス (id = 1952912699) が追加されていることがわかります.
この追加によって, この RectangleFigure クラスのインスタンスに対応する矩形が選択状態になります.
課題A4では, JHotDrawのシステム内部で, 配置された図形がどのように管理されているかを調べるため, この RectangleFigure クラスのインスタンスがどこから来たのかを確認していきます.

まずは RectangleFigure がどこから来たのかを見るために, 呼び出しスタック上で1つ呼び出し元をクリックしてください.
ここで, ソースコードを見ると, 先ほど呼び出されていた addToSelection(Figure) メソッドは, ローカル変数 view で参照されているインスタンスに対する呼び出しであり,
その実引数としてフィールド anchorFigure の値が渡されていることがわかります.
また, 変数ビュー上の this を開くと, このフィールドは DefaultDragTracker クラスのインスタンス (id = 758826749) のフィールドであることがわかります.

ここでは, いったんローカル変数 view の値がどこから来たのかを見ていきます.
ステップバックオーバーを4回押して98行目に戻ってください.
ソースコードを見ると, getView() メソッドの戻り値を ローカル変数 view に代入していることが確認できます.
ここで, この戻り値がどうなっているのかを確認するために, ステップインを1回押して getView() メソッドの中に前から入ってください.

AbstractTool クラスの getView() メソッドに入りました.
ここで, 変数ビュー上の this を開くと, DefaultDragTracker クラスのインスタンス (id = 758826749) の editor フィールドが
DefaultDrawingEditor クラスのインスタンス (id = 1859859960) を参照していることがわかります.
これを確認したら, ステップインを3回押して DefaultDrawingEditor クラスの getAcitiveView() メソッドの中に前から入ってください.

DefaultDrawingEditor クラスの getActiveView() メソッドに入りました.
ここで, 変数ビュー上の this を開くと, DefaultDrawingEditor クラスのインスタンス (id = 1859859960) の
フィールド activeView が DefaultDrawingView クラスのインスタンス (id = 150367587) を参照していることがわかります.

先ほどの結果から, DefaultDrawingView クラスのインスタンス (id = 150367587) は
DefaultDrawingEditor クラスのインスタンス (id = 1859859960) が参照していることがわかりました.
呼び出しスタック上で2つ呼び出し元である DefaultDragTracker クラスの mousePressed(MouseEvent) メソッドをクリックしてください.

現在は, 呼び出し元である DefaultDragTracker クラスの mousePressed(MouseEvent) メソッドの98行目を見ています.
今までの結果から, DefaultDrawingView クラスのインスタンス (id = 150367587) がどのようにして来たのかがわかりました.
ここからは, RectangleFigure クラスのインスタンス (id = 1952912699) がどこから来たのかを見ていきます.
ここで, 変数ビュー上の this を開き, その中にある anchorFigure を右クリックしてください.
右クリックするとポップアップメニューが現れるので, 「値の代入時点に飛ぶ」を選択してください.

「値の代入時点に飛ぶ」を選択すると, DefaultDragTracker クラスのインスタンス (id = 758826749) の anchorFigure フィールドに
この RectangleFigure クラスのインスタンス (id = 1952912699) への参照が代入された時点である
DefaultDragTracker クラスの setDraggedFigure(Figure) メソッドの218行目にまで現在の実行時点が遡ります.
まずは, 「実行時点の登録」ビューの追加ボタンをクリックして実行時点の登録を行ってください.
ここでは, DefaultDragTracker クラスのフィールド anchorFigure に仮引数 f の値を代入していることが確認できます.
仮引数 f の値がどこから来たのかを見るために, 呼び出しスタック上で1つ呼び出し元をクリックしてください.

現在は, 呼び出し元である SelectionTool クラスの getDragTracker() メソッド見ています.
ここで 変数ビュー上の 「呼び出し前」および this を開くと, 先ほどの setDraggedFigure (Figure) メソッドが呼び出されている
DefaultDragTracker クラスのインスタンス (id = 758826749) は, DelegationSelectionTool クラスのインスタンス (id = 5999587451) の
dragTracker フィールドによって参照されていることがわかります.
引き続き, 仮引数 f の値がどこから来ているのかを見るために, 呼び出しスタック上でさらに1つ呼び出し元をクリックしてください.

現在は, 呼び出し元である DelegationSelectionTool クラスの mousePressed(MouseEvent) メソッドを見ています.
ここで, ソースコードを見ると, ここではローカル変数 figure の値が実引数として渡されていることが確認できます.

今度はこのローカル変数 figure の値がどこから来ているのかを見るために, ステップバックオーバーを3回押して270行目に戻ってください.
270行目では, ローカル変数 view で参照されるインスタンスに対して findFigure(Point) メソッドが呼び出され,
その戻り値がローカル変数 figure に代入されていることが確認できます.
この戻り値がどうなっているのかを確認するために, ステップインでこのメソッドの中に前から入ってください.

DefaultDrawingView クラスの findFigure(Point) メソッドに入りました.
ここで, ソースコードを見ると, このメソッドでは getDrawing() メソッドで取得してきたインスタンスに対して,
findFigure(Point2D$Double) メソッドが呼び出され, その戻り値を返していることが確認できます.
これを確認したら, ステップインを2回押して, getDrawing() メソッドの中に前から入ってください.

DefaultDrawingView クラスの getDrawing() メソッドに入りました.
ここで, 変数ビュー上の this を開くと, DefaultDrawingView クラスのインスタンス (id = 150367587) の
フィールド drawing が QuadTreeDrawing クラスのインスタンス (id = 1583174451) を参照していることがわかります.
これを確認したら, ステップリターンを1回押して呼び出し元に戻ってください.

DefaultDrawingView クラスの findFigure(Point) メソッドに戻ってきました.
ここでは, まずステップネクストを1回押して viewToDrawingPoint(Point) メソッドの呼び出しを飛ばし,
それから, ステップインを1回押して QuadTreeDrawing クラスの findFigure(Point2D$Double) メソッドの中に前から入ってください.

QuadTreeDrawing クラスの findFigure(Point2D$Double) メソッドに入りました.
ここでは, ステップインを3回押して QuadTree クラスの findContains(Point2D$Double) メソッドの中に前から入ってください.

QuadTree クラスの findContains(Point2D$Double) メソッドに入りました.
ここで, 変数ビュー上の this を開くとQuadTree クラスのインスタンス (id = 808853315) のフィールド root が
QuadTree の内部クラス QuadNode クラスのインスタンス (id = 2120356010) を参照していることがわかります.
ここでは, ステップオーバーを1回押して83行目に進んだあと, ステップインを2回押して,
QuadTree$QuadNode クラスの findContains(Point2D$Double, HashSet) メソッドの中に前から入ってください.

QuadTree$QuadNode クラスの findContains(Point2D$Double, HashSet) メソッドに入りました.
ここで, 変数ビュー上の this を開くと, QuadTree$QuadNode クラスのインスタンスの
フィールド objects が HashMap のインスタンスを参照していることがわかります.

ここでは, ステップオーバーを3回押して226行目まで進んだあと, ステップネクストを2回押してください.
ソースコードを見ると, 224行目の拡張for文で 先ほど確認した HashMap から取得してきた要素を用いて,
226行目ではそのうちのキー要素だけを取り出して, それを仮引数 result で参照されている HashSet オブジェクトに追加していることが確認できます.
ここで, 変数ビュー上の「呼び出し後」 (Entry.getKey() の呼び出し後) および「呼び出し前」 (HasSet.add(Object) の呼び出し前) を開くと,
実際に RectangleFigure クラスのインスタンス (id = 1952912699) を取得してから追加していることを確認できます.
これを確認したら, ステップオーバーを4回押して呼び出し元に戻ってください.

呼び出し元である QuadTree クラスの findContains(Point2D$Double) メソッドの84行目に戻ってきました.
ここでは, ステップオーバーを1回押して, このメソッド内ではローカル変数 result に何もオブジェクトが追加されず,
89行目の return result に現在の実行時点が移ることを確認してください.
これを確認したら, 呼び出しスタック上で1つ呼び出し元をクリックしてください.

現在は QuadTreeDrawing クラスの findFigure(Point2D$Double) メソッドを見ています.
ここでは, まずステップオーバーを2回押して129行目まで進んでください.
129行目で「実行時点の登録」ビューの追加ボタンをクリックして実行時点の登録を行ってください.

現在は QuadTreeDrawing クラスの findFigure(Point2D$Double) メソッドの129行目にいます.
そのあと, ステップネクストを3回実行すると, 現在の実行時点が130行目に移ります.
ここで, 変数ビュー上の「呼び出し後」 (Iterator.next() の呼び出し後) を開き, 戻り値が RectangleFigure クラスの
インスタンス (id = 1952912699) であることを確認してください.
これを確認したら, 呼び出しスタック上で2つ呼び出し元をクリックしてください.

ここまでの結果から RectangleFigure クラスのインスタンスに関わる各オブジェクトの関係について, 以下のことがわかりました.

  1. RectangleFigure クラスのインスタンス (id = 1952912699) は QuadTree の内部クラス QuadNode クラスのインスタンス (id = 2120356010) が参照している.
  2. QuadTree の内部クラス QuadNode クラスのインスタンス (id = 2120356010) は QuadTree クラスのインスタンス (id = 808853315) が参照している.
  3. QuadTree クラスのインスタンス (id = 808853315) は QuadTreeDrawing クラスのインスタンス (id = 1583174451) が参照している.
  4. QuadTreeDrawing クラスのインスタンス (id = 1583174451) は DefaultDrawingView クラスのインスタンス (id = 150367587) が参照している.
ここからは, DefaultDrawingView クラスのインスタンス (id = 150367587) がどこから来たのかを見ていきます.
現在は, 呼び出し元である SelectionTool クラスの mousePressed(MouseEvent) メソッドの270行目を見ています.
ここで, ソースコードを見ると, この DefaultDrawingView クラスのインスタンスはローカル変数 view で参照されていることが確認できます.

このローカル変数 view の値がどこから来たのかを見るために, ステップバックオーバーを10回押して228行目にまで戻ってください.
228行目では, ローカル変数 view に getView() メソッドの戻り値を代入していることが確認できます.
ここで, この戻り値がどうなっているのかを確認するために, ステップインを1回押して getView() メソッドの中に前から入ってください.

AbstractTool クラスの getView() メソッドに入りました.
ここで, 変数ビュー上の this を開くと, DelegationSelectionTool クラスのインスタンス (id = 599587451) の editor フィールドが
DefaultDrawingEditor クラスのインスタンス (id = 1859859960) を参照していることがわかります.
これを確認したら, ステップインを3回押して DefaultDrawingEditor クラスの getAcitiveView() メソッドの中に前から入ってください.

DefaultDrawingEditor クラスの getAcitiveView() メソッドに入りました.
ここで, 変数ビュー上の this を開くと, DefaultDrawingEditor クラスのインスタンス (id = 1859859960) の
フィールド activeView が DefaultDrawingView クラスのインスタンス (id = 150367587) を参照していることがわかります.

先ほどの結果から, DefaultDrawingView クラスのインスタンス (id = 150367587) は
DefaultDrawingEditor クラスのインスタンス (id = 1859859960) が参照していることがわかりました.
呼び出しスタック上で2つ呼び出し元をクリックしてください.
ここで, 課題A4は終了です. 時間計測を終了してください.


課題A4の機能理解が終了しましたら, 以下のアンケートにお答えください.

アンケート回答

次へ