Javaにおけるオブザーバパターン
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
アプローチを使用することをお勧めします。