質問者さんに限らず
「クラスの連携がわからない」=>「あるクラスから別のクラスをどうやって利用すればいいかわからない」
といったご質問を割合よく目にする気がします。個人的な推測ですが、こうした状況に直面しておられる初心者の方の課題は以下のようなものではないかと思います。
(A) (JavaFXに限らず)クラスライブラリーは特定の機能をもったインスタンスを提供することを狙っている
一方、クラスライブラリーを利用するプログラマーの認識は
(B) クラスを単なる機能の集まりとして捉えている
(C) インスタンス同士の関係を捉えていない
つまり設計の際に機能の連携を「クラス同士の関係」として(謂わば短絡的に)捉えようとしているのではないでしょうか?
どのようなインスタンスの関係となっているべきかを考えると設計が見えてきやすくなるような気がします。MVC的なシナリオで設計を考えた時JavaFXでの登場人物たちもそれに当てはめて考えることができます。
外観を表現するもの。またユーザーアクションにより発生するイベントが通知される先でもある。javafx.scene.Nodeの派生クラスのインスタンスだが、アプリケーションで複数個所に出てくるような「ある一定の振る舞いを備えた部品」としない限りは派生クラスを定義する必要は必ずしもない。
アプリ独自のなんらかのオブジェクト。GUI/CUIどちらの種類のアプリでも同じクラスのインスタンスでよいという心構えで設計する。
VIEWとMODELの連携を司るもの。GUIアプリ固有。VIEWへ通知されたイベントを捉えて他のVIEW/MODELへ何かをさせたり、MODELの動作結果をVIEWへ反映させたりする調停役。
上記のインスタンスの関係は典型的に次のように設計することが多い気がします。
text
1CONTROLLER
2 |
3 +------ has a -----> VIEW(@FXMLアノテーション付きのフィールドに保持)
4 |
5 +------ has a -----> MODEL(プログラマー独自フィールドに保持)
こうするのはコントローラーがVIEWとMODELの調停役だからです。
質問者さんのクラスCが「移動処理を行うクラス」となっていますが、「処理をするクラス」といういい方しかできないとすれば、それを「クラスにするべきなのかちょっと待って」と言いたくなります。大事なのは「クラスはインスタンスを定義するために設計するもの」という点で、極論を言えばインスタンスをイメージできないのならそれはクラスではないといってもよいと思います。
もしクラスCを「ある将棋の局面を表すもの」として、それが
「その局面で特定位置にどんな駒があるか知っている」
「その局面で特定の駒を移動できるか否かの判定ができる」
「駒を移動したとき局面がどう変化するか計算できる」
という機能を持つものとして捉えるなら、これをMODELとしてそのインスタンスをCONTROLLERが保持するのが自然に感じます。
CONTROLLERはVIEWもMODELも両方のインスタンスを「知って」います。そのため初期化メソッドなどで「このVIEWにこういうことが起きたらMODELに対して何かする」というのを自然に定義できます。クラスの連携じゃなくてインスタンスの連携をイメージしてみてください。
Java
1class 将棋アプリ extends Application {
2 // ビューやコントローラーのライフサイクルより長いものとしてモデルを捉える
3 // こうすれば画面遷移を導入してもモデルはちゃんと同一のものが使われる
4 private Board board = new Board();
5
6 @Override public void start(Stage stage) throws Exception {
7 FXMLLoader loader = new FXMLLoader(...);
8 Parent root = loader.load();
9 Controller controller = loader.getController();
10 controller.setBoard(board); // モデルをコントローラーへ教える
11 stage.setScene(new Scene(root));
12 stage.show();
13 }
14}
15
16
17class Controller {
18 // コントローラーはアプリケーションインスタンスを意識しない
19 // 下手に意識すると画面遷移などを自由に設計しづらくなる
20 @FXML private GridPane boardPane;
21
22 private Board board;
23
24 public void setBoard(Board board) {
25 this.board = board;
26 }
27
28 @FXML private void initialize() {
29 for (int i = 0; i < 64; i++) {
30 int row = i / 8;
31 int col = i % 8;
32 StackPane stack = new StackPane();
33 // 簡単のため、ある位置がクリックされたらモデルへ行・列位置を通知するとしてます
34 stack.setOnMouseClicked(event -> board.xxxx(row, col));
35 }
36 ...
37 }
38}
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2018/03/20 01:22
2018/03/20 01:38
2018/03/20 01:45