1概要

この記事では、Observerパターンについて説明し、いくつかのJava実装の選択肢を見ていきます。


2オブザーバパターンとは何ですか?

観察者は行動デザインパターンです。オブジェクト間の通信、つまり

observable



observers

を指定します。

観察可能

は、その状態の変化について観察者__に通知するオブジェクトです。

たとえば、通信社は、ニュースを受信したときにチャンネルに通知できます。

ニュースを受信することは、通信社の状態を変えるものであり、それはチャンネルに通知されるようにします。

それを自分で実装する方法を見てみましょう。

まず、

NewsAgency

クラスを定義しましょう。

public class NewsAgency {
    private String news;
    private List<Channel> channels = new ArrayList<>();

    public void addObserver(Channel channel) {
        this.channels.add(channel);
    }

    public void removeObserver(Channel channel) {
        this.channels.remove(channel);
    }

    public void setNews(String news) {
        this.news = news;
        for (Channel channel : this.channels) {
            channel.update(this.news);
        }
    }
}


NewsAgency

は観測可能であり、

news

が更新されると、

NewsAgency

の状態が変化します。変更が発生すると、

NewsAgency



update()

メソッドを呼び出してこの事実についてオブザーバに通知します。

それを可能にするために、観察可能なオブジェクトは、観察者への参照を保持する必要があります。** 私たちの場合、それは

channels

変数です。

それでは、オブザーバ、つまり__Channelクラスがどのように見えるかを見てみましょう。


NewsAgency

の状態が変化したときに呼び出される

update()

メソッドが必要です。

public class NewsChannel implements Channel {
    private String news;

    @Override
    public void update(Object news) {
        this.setNews((String) news);
    }
}


Channel

インタフェースにはメソッドが1つだけあります。

public interface Channel {
    public void update(Object o);
}

さて、オブザーバーのリストに

NewsChannel

のインスタンスを追加し、

NewsAgency

の状態を変更すると、

NewsChannel

のインスタンスが更新されます。

NewsAgency observable = new NewsAgency();
NewsChannel observer = new NewsChannel();

observable.addObserver(observer);
observable.setNews("news");
assertEquals(observer.getNews(), "news");

Javaコアライブラリには事前定義された

Observer

インタフェースがあり、これによってオブザーバパターンの実装がさらに簡単になります。それを見てみましょう。


3

Observer


による実装



java.util.Observer


インタフェースは

update()

メソッドを定義しているので、独自に定義する必要はありません前のセクションで行ったように。

実装でそれを使用する方法を見てみましょう。

public class ONewsChannel implements Observer {

    private String news;

    @Override
    public void update(Observable o, Object news) {
        this.setNews((String) news);
    }
}

ここで、2番目の引数は、以下で見るように

Observable

から来ています。

観測量を定義するには、Javaの

Observable

クラスを拡張する必要があります。

public class ONewsAgency extends Observable {
    private String news;

    public void setNews(String news) {
        this.news = news;
        setChanged();
        notifyObservers(news);
    }
}

オブザーバの

update()

メソッドを直接呼び出す必要はないことに注意してください。

stateChanged()



notifyObservers()

を呼び出すだけで、残りの部分は

Observable

クラスによって行われます。

また、オブザーバのリストが含まれており、そのリストを管理するためのメソッド(

addObserver()

および__deleteObserver())を公開しています。

結果をテストするには、このリストにオブザーバを追加してニュースを設定するだけです。

ONewsAgency observable = new ONewsAgency();
ONewsChannel observer = new ONewsChannel();

observable.addObserver(observer);
observable.setNews("news");
assertEquals(observer.getNews(), "news");


Observer

インターフェースは完璧ではなく、Java 9以降廃止予定です。その欠点の1つは、

Observable

がインターフェースではなくクラスであるということです。そのため、サブクラスをオブザーバブルとして使用できないのです。

また、開発者は

Observable

の同期メソッドのいくつかをオーバーライドしてスレッドの安全性を妨げる可能性があります。



ProperyChangeListener


インタフェースを見てみましょう。


4

PropertyChangeListener


を使用した実装

  • この実装では、監視可能オブジェクトはhttps://docs.oracle.com/javase/8/docs/api/java/beans/PropertyChangeSupport.html[

    PropertyChangeSupport

    ]インスタンスへの参照を保持する必要があります。クラスのプロパティが変更されたときにオブザーバに通知します。

観測量を定義しましょう。

public class PCLNewsAgency {
    private String news;

    private PropertyChangeSupport support;

    public PCLNewsAgency() {
        support = new PropertyChangeSupport(this);
    }

    public void addPropertyChangeListener(PropertyChangeListener pcl) {
        support.addPropertyChangeListener(pcl);
    }

    public void removePropertyChangeListener(PropertyChangeListener pcl) {
        support.removePropertyChangeListener(pcl);
    }

    public void setNews(String value) {
        support.firePropertyChange("news", this.news, value);
        this.news = value;
    }
}

この

support

を使用して、オブザーバを追加および削除し、オブザーバブルの状態が変化したときに通知することができます。

support.firePropertyChange("news", this.news, value);

ここで、最初の引数は監視対象プロパティの名前です。 2番目と3番目の引数はそれに応じてその古い値と新しい値です。

オブザーバは


PropertyChangeListener


を実装する必要があります。

public class PCLNewsChannel implements PropertyChangeListener {

    private String news;

    public void propertyChange(PropertyChangeEvent evt) {
        this.setNews((String) evt.getNewValue());
    }
}

配線を行っている

PropertyChangeSupport

クラスにより、イベントから新しいプロパティ値を復元できます。

それがまた働くことを確かめるために実装をテストしましょう:

PCLNewsAgency observable = new PCLNewsAgency();
PCLNewsChannel observer = new PCLNewsChannel();

observable.addPropertyChangeListener(observer);
observable.setNews("news");

assertEquals(observer.getNews(), "news");


5結論

この記事では、

Observer

デザイン・パターンをJavaで実装する2つの方法を検討しましたが、

PropertyChangeListener

アプローチを使用することをお勧めします。