1. はじめに
今回はJavaの標準APIであるPropertyChangeListener
を利用して、プロパティが変更されたことを検知する方法について説明したいと思います。
JavaのGUIアプリであるSWTやSwing,AWTではイベントを検知する処理はよく知られていますが、普通のJavaクラスでもプロパティが変更されたイベントを検知する仕組みが用意されています。
2. 実装
2.1. チェック対象のクラス
package com.example.demo;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
public class Item {
private int price;
// ★ポイント1
private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);
// ★ポイント2
public void addPropertyChangeListener(PropertyChangeListener listener) {
this.pcs.addPropertyChangeListener(listener);
}
// ★ポイント3
public void removePropertyChangeListener(PropertyChangeListener listener) {
this.pcs.removePropertyChangeListener(listener);
}
public int getPrice() {
return price;
}
// ★ポイント4
public void setPrice(int price) {
int oldPrice = this.price;
this.price = price;
this.pcs.firePropertyChange("price", oldPrice, price);
}
// generated by eclipse
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("Item [price=");
builder.append(price);
builder.append("]");
return builder.toString();
}
}
★ポイント1
java.beans.PropertyChangeSupport
のインスタンスを生成し、フィールドとして定義します。
PropertyChangeSupport
のコンストラクタ引数はイベントの発生元(検知対象)のオブジェクトのためthis
を指定します。
★ポイント2
java.beans.PropertyChangeListener
を★ポイント1で定義したPropertyChangeSupport
に追加するメソッドを実装します。
★ポイント3
PropertyChangeSupport
からjava.beans.PropertyChangeListener
を削除するメソッドを実装します。
★ポイント2、★ポイント3はセットで実装するお決まりのものだと思ってください。
★ポイント4
PropertyChangeSupport
のfirePropertyChange
メソッドでプロパティの変更イベントを発生させます。
- 第1引数 : 変更されたプロパティ名。文字列で指定するので間違えないように!
- 第2引数 : 変更前のプロパティの値
- 第3引数 : 変更後のプロパティの値
package com.example.demo;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
public class Person {
private String name;
private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);
public void addPropertyChangeListener(PropertyChangeListener listener) {
this.pcs.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
this.pcs.removePropertyChangeListener(listener);
}
public String getName() {
return name;
}
public void setName(String name) {
String oldName = this.name;
this.name = name;
this.pcs.firePropertyChange("name", oldName, name);
}
// generated by eclipse
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("Person [name=");
builder.append(name);
builder.append("]");
return builder.toString();
}
}
2.2. 変更されたことを検知するクラス
package com.example.demo;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
// ★ポイント5
public class DemoListener implements PropertyChangeListener {
// ★ポイント6
@Override
public void propertyChange(PropertyChangeEvent evt) {
// ★ポイント7
Object eventTriggerObject = evt.getSource();
String propertyName = evt.getPropertyName();
// ★ポイント8
if (Item.class.isInstance(eventTriggerObject)) {
if ("price".equals(propertyName)) {
// ★ポイント9
Integer oldValue = (Integer) evt.getOldValue();
Integer newValue = (Integer) evt.getNewValue();
System.out.println("[Item.price] oldValue:" + oldValue + " -> newValue:" + newValue);
}
} else if (Person.class.isInstance(eventTriggerObject)) {
if ("name".equals(propertyName)) {
String oldValue = (String) evt.getOldValue();
String newValue = (String) evt.getNewValue();
System.out.println("[Person.name] oldValue:" + oldValue + " -> newValue:" + newValue);
}
}
}
}
★ポイント5
java.beans.PropertyChangeListener
インターフェースを実装したクラスを定義します。
★ポイント6
propertyChange
メソッドをオーバーライドしてプロパティの変更イベントをハンドリングする処理を実装します。
★ポイント7
java.beans.PropertyChangeEvent
のgetSource()
メソッドで変更イベントの発生元のオブジェクトを取得します。
また、変更されたプロパティはgetPropertyName()
メソッドでプロパティ名が取得できるので、これを利用して特定します。
★ポイント8
今回はItem
クラスとPerson
クラスの2つにリスナを登録しているため、どちらのインスタンスが発生元か判断する必要があります。
★ポイント9
プロパティの変更前の値はgetOldValue()
メソッド、変更後の値はgetNewValue()
メソッドでそれぞれ取得します。
戻り値はObject
なので、プロパティのデータ型に応じてキャストする必要があります。
2.3. 動作確認のデモアプリのクラス
package com.example.demo;
public class App {
public static void main(String[] args) {
Item item = new Item();
System.out.println(item);
item.setPrice(500);
System.out.println(item);
DemoListener demoListener = new DemoListener();
item.addPropertyChangeListener(demoListener);
item.setPrice(700);
item.setPrice(1000);
Person person = new Person();
System.out.println(person);
person.setName("Taro");
System.out.println(person);
person.addPropertyChangeListener(demoListener);
person.setName("5zm");
person.setName("Yamada");
item.removePropertyChangeListener(demoListener);
person.removePropertyChangeListener(demoListener);
}
}
3. 実行結果
Item [price=0]
Item [price=500]
[Item.price] oldValue:500 -> newValue:700
[Item.price] oldValue:700 -> newValue:1000
Person [name=null]
Person [name=Taro]
[Person.name] oldValue:Taro -> newValue:5zm
[Person.name] oldValue:5zm -> newValue:Yamada
addPropertyChangeListener
でリスナを追加する前はsetter
で値を設定しても何も起こらず、リスナを追加した後は変更した内容がリスナによって検知されていることが分かるかと思います。
4. さいごに
今回はJavaの標準APIであるPropertyChangeListener
を利用して、プロパティが変更されたことを検知する方法について説明しました。
PropertyChangeListener
を利用することで、特別なライブラリ等を準備することなく、手軽にイベント処理を試せるかと思います。