質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
86.02%
JavaFX

JavaFXとは、Java仮想マシン上で動作するリッチインターネットアプリケーション (RIA) のGUIライブラリです。Swingとは異なり、FXMLと呼ばれる XMLとCSSを併用してデザインを記述します。

Q&A

解決済

JavaFXにおけるObserverパターンの実装方法

hilty8
hilty8

総合スコア15

JavaFX

JavaFXとは、Java仮想マシン上で動作するリッチインターネットアプリケーション (RIA) のGUIライブラリです。Swingとは異なり、FXMLと呼ばれる XMLとCSSを併用してデザインを記述します。

1回答

0グッド

0クリップ

1834閲覧

投稿2018/03/12 06:10

デザインパターンを勉強しています。
java.util.observer, java.util.observable を用いたObserverパターンを実装してみたのですが、期待通りに動いてくれません。

期待した動作

Subject = Boardクラス
Observer = MrObserverクラス
Boardクラスにあるボタンをクリックすると、MrObserverがそれを感知し、MrObserverが所有するRectangleの大きさと色が変わる、という動作を期待しています。

考えていること

Observerパターンは、以下の条件を満たせば機能すると考えています。抜け、漏れ、誤解などありましたら教えてくださると助かります。
1、Observer「MrObserver」は、implements Observer を実装
2、Subject「Board」は、Observableを継承
3、addObserverメソッドにより、Subjectは、Observerを把握
4、Subjectが何処かでnotifyObservers()を実行する
5、Observerのupdate()に処理してほしい内容を書く

Observerパターンについて、notifyObservers(), update()メソッドについて、以下の様に理解していますが、
その具体的なやり方がわかりません。
・SubjectがnotifyObservers()を実行すると、観察者側のupdate()メソッドが実行される
・notifyObservers()、update()のメソッドには引数を指定でき、そこでデータのやり取りが出来る

聞きたいこと

期待通りの結果にならない理由について、指定していただきたいと考えています。
宜しくお願い致します。

ソースコード

java

1public class JavaFX12 extends Application{ 2 3 @Override 4 public void start(Stage primaryStage) { 5 Board board = new Board(); 6 MrObserver observer = new MrObserver(); 7 board.addObserver(observer); 8 9 GridPane grid = board.grid; 10 GridPane grid2 = observer.grid; 11 VBox vbox = new VBox(); 12 vbox.getChildren().addAll(grid,grid2); 13 14 StackPane root = new StackPane(); 15 root.getChildren().add(vbox); 16 17 Scene scene = new Scene(root, 300, 250); 18 19 primaryStage.setScene(scene); 20 primaryStage.show(); 21 } 22 23 public static void main(String[] args) { 24 launch(args); 25 } 26}

java

1public class Board extends Observable{ 2 GridPane grid; 3 public Board(){ 4 grid = new GridPane(); 5 6 Button btn = new Button(); 7 btn.setOnAction((ActionEvent event) -> { 8 notifyObservers("string"); 9 }); 10 grid.add(btn, 0, 1); 11 } 12}

java

1public class MrObserver implements Observer{ 2 GridPane grid; 3 Rectangle rect; 4 public MrObserver(){ 5 grid = new GridPane(); 6 rect = new Rectangle(50,50); 7 rect.setFill(Color.RED); 8 grid.add(rect, 0, 0); 9 } 10 @Override 11 public void update(Observable o, Object arg) { 12 rect = new Rectangle(100,100); 13 rect.setFill(Color.BLUE); 14 } 15}

気になる質問をクリップする

クリップした質問は、後からいつでもマイページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

下記のような質問は推奨されていません。

  • 質問になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

適切な質問に修正を依頼しましょう。

回答1

2

ベストアンサー

###通知の仕組み

java.util.Observableが自分の変化を監視者へ通知する際には「変わった」とマークしないと通知されないみたいです。

notifyObservers("string");
だけでは何もおこらずその前に
setChanged();
を呼び出す必要があるのですね。

こうなっている理由はObservableのデザインパターンとは多分直接関係なくて「複雑な状態を持つような一般的なObservableを設計する際に変化をどうやって手際よく通知するか」に関することだと思います。

Observableの処理の中で

あっちの処理やって
こっちの処理やって
そっちの処理やって
最後に「変化があれば通知する」

というような作りが便利ということなのでしょう。あっちこっちの処理のどこかで「状態変わった」ということが認識できたらsetChanged()とやっておくわけです。そうして処理の元締めへ戻った時「もしどこかで変化が起きていたら通知」とやるわけですね。内部状態の一つ一つが変化するごとに通知していたのでは効率的な問題、あるいは「状態変化が中途半端な状態で監視者がObservableの状態を調べ始めること」が都合が悪いためにこうなっていると思います。


ちなみにMrObserver#updateはせっかく呼び出されても期待する画面の変更は起きません。なぜなら「新たにRectangleを生成しているだけ」であってそれをJavaFXのシーングラフへ追加していないからです。

考え方を変えてください。既にシーングラフにRectangleのインスタンスがくっついている状態でupdateが呼ばれるのですからそのRectangleインスタンスの状態を変更すればよいのです。

Java

1rect.setWidth(100); 2rect.setHeight(100); 3rect.setFill(Color.BLUE);

「え・・・WidthやHeightを変えるだけで画面が変わるの?」と思われるかも知れません。JavaFXのNode(画面上に表示されている全てのもの)が持つwidth, height, fillといった変更可能プロパティーはjavafx.beans.Observableという監視可能なオブジェクトでして、その値を変更するとそれが自動的に画面に反映される仕組みになっているのです。これはJavaFXに限ったことではなく大抵のGUIシステムでそんな感じだと思います。Androidしかり、Unityしかり、Windows Formアプリしかりです。

投稿2018/03/12 08:56

編集2018/03/12 09:37
KSwordOfHaste

総合スコア18380

unz.hori, hilty8👍を押しています

下記のような回答は推奨されていません。

  • 質問の回答になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

このような回答には修正を依頼しましょう。

回答へのコメント

KSwordOfHaste

2018/03/12 08:58

あ、言い忘れました。java.util.Observableはdeprecatedなクラスでして、JavaFXを使う場合このクラスは使いません。javafx.beansパッケージの中にある様々なクラス(javafx.beans.Observableの派生クラス)の方を使います。
hilty8

2018/03/13 05:49

setChanged() が必要だったのですね。失念していました。 Observerパターンの考え方(組み込み方?)に関して説明していただき、ありがとうございます。なかなか解説が見つからなくて苦労していたので助かります。 JavaFXはSwingとは異なり、シーングラフを再描画するよう命令する必要はない、というのはそういうことだったのですね。スッキリしました。 javafx.beansパッケージ内のクラスについて調べてみます。有り難うございました。
hilty8

2018/03/13 05:59

すみません、javafx.beansパッケージの中にある、javafx.beans.Observableの派生クラスについて調べる方法についても教えていただけないでしょうか。 現在はOracleのdocsから、Observableを実装したクラスの一覧を見ているのですが、それぞれのクラスの使い方など、どのように把握するものなのでしょうか?
KSwordOfHaste

2018/03/13 07:33 編集

自分の場合は殆どがAPIリファレンスだよりです。クラスにはその機能を表す首尾一貫した機能が揃っているはずです。どういう機能なのかはメソッドの一覧を概観すると大雑把にではあますがイメージを掴みやすいと思います。似た設計のクラスに触れたことがあればそこから類推することでも全体像をつかみやすくなります。どう使うかリファレンスだけではわかりにくい場合は実際のサンプルを探してみたりします。
KSwordOfHaste

2018/03/13 07:39

あ、javafx.beansパッケージの中身のクラス群はクラスやインターフェースが錯綜していて分かりにくいと思います。その点、最初からリファレンス首っ引きで理解しようとすると混乱すると思います。まずはPropertyを中心にみていくとよいでしょう。一番よく使うものです。その後でBinding(複数のObservableなものに依存して値が自動的に決まる仕組み)について知る際に関係するクラスから順に知っていけばよいと思います。
hilty8

2018/03/13 08:19

具体的に教えてくださって有り難うございます。 メソッドの一覧を概観する→イメージを掴む→わかりにくかったらサンプルを探す ですね。早速やってみます。 javafx.beans.property のことですよね。読んでみます。 回答有り難うございました!
KSwordOfHaste

2018/03/13 09:04

> javafx.beans.property おっしゃるとおりです。

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
86.02%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問

同じタグがついた質問を見る

JavaFX

JavaFXとは、Java仮想マシン上で動作するリッチインターネットアプリケーション (RIA) のGUIライブラリです。Swingとは異なり、FXMLと呼ばれる XMLとCSSを併用してデザインを記述します。