LoginSignup
10
10

More than 5 years have passed since last update.

JavaのPropertyChangeListenerでプロパティが変更されたことを検知する

Posted at

1. はじめに

今回はJavaの標準APIであるPropertyChangeListenerを利用して、プロパティが変更されたことを検知する方法について説明したいと思います。

JavaのGUIアプリであるSWTやSwing,AWTではイベントを検知する処理はよく知られていますが、普通のJavaクラスでもプロパティが変更されたイベントを検知する仕組みが用意されています。

2. 実装

2.1. チェック対象のクラス

Item.java
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
PropertyChangeSupportfirePropertyChangeメソッドでプロパティの変更イベントを発生させます。

  • 第1引数 : 変更されたプロパティ名。文字列で指定するので間違えないように!
  • 第2引数 : 変更前のプロパティの値
  • 第3引数 : 変更後のプロパティの値
Person.java
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. 変更されたことを検知するクラス

DemoListener.java
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.PropertyChangeEventgetSource()メソッドで変更イベントの発生元のオブジェクトを取得します。
また、変更されたプロパティはgetPropertyName()メソッドでプロパティ名が取得できるので、これを利用して特定します。

★ポイント8
今回はItemクラスとPersonクラスの2つにリスナを登録しているため、どちらのインスタンスが発生元か判断する必要があります。

★ポイント9
プロパティの変更前の値はgetOldValue()メソッド、変更後の値はgetNewValue()メソッドでそれぞれ取得します。
戻り値はObjectなので、プロパティのデータ型に応じてキャストする必要があります。

2.3. 動作確認のデモアプリのクラス

App.java
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を利用することで、特別なライブラリ等を準備することなく、手軽にイベント処理を試せるかと思います。

10
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
10