シンプルなオブザーバーパターンの実装
次のようにコードをコピーします。
java.util.ArrayListをインポートします。
java.util.Collectionsをインポートします。
java.util.Iteratorをインポートします。
java.util.Listをインポートします。
/**
* コールバックはオブザーバー モードで使用されます。
* A. オブザーバーは自身を監視対象のリスナー リストに登録し、オブザーバー クラス自体がコールバック関数を提供します
* B. Observable (Observable または Subject) はオブザーバーのリストを維持し、オブザーバーを登録および登録解除できます。
* C. オブザーバーのステータスが変化すると、notifyObservers() を呼び出すことができます。このメソッドはオブザーバー リストを走査し、1 つずつ呼び出します。
オブザーバーが提供するコールバック関数
* @author は
*
*/
パブリック クラス SimpleObserverPattern {
public static void main(String[] args) {
SimpleObserverPattern SOP = new SimpleObserverPattern();
List<IObserver> オブザーバー = new ArrayList<IObserver> ();
IObserver オブザーバーA = sop.new Observer("ObserverA");
IObserver オブザーバーB = sop.new Observer("ObserverB");
オブザーバーズ.add(オブザーバーA);
オブザーバーズ.add(オブザーバーB);
IObservable observable = sop.new Observable(observers);
observable.registerObserver(sop.new Observer("ObserverC"));
observable.changeState();
observable.close();
}
// 観察される人のことを Subject と呼ぶ場合もあります。
インターフェイス IObservable {
void registerObserver(IObserver オブザーバー);
void unregisterObserver(IObserver オブザーバー);
void notificationObservers();
文字列 getState();
void changeState();
void close();
}
class Observable は IObservable {を実装します
プライベート静的最終文字列 NEW = "新しい";
private static Final String CHANGED = "変更されました";
プライベート静的最終文字列 CLOSED = "クローズ";
プライベート文字列の状態。
private List<IObserver> オブザーバー。
public Observable() {
これ(null);
}
public Observable(List<IObserver> オブザーバー) {
if(オブザーバー == null) {
オブザーバー = new ArrayList<IObserver> ();
}
this.observers = Collections.synchronizedList(observers);
this.state = NEW;
}
@オーバーライド
public void registerObserver(IObserver オブザーバー) {
オブザーバー.add(オブザーバー);
}
@オーバーライド
public void unregisterObserver(IObserver オブザーバー) {
オブザーバー.削除(オブザーバー);
}
@オーバーライド
public void NoticeObservers() {
Iterator<IObserver> iter = observers.iterator();
while(iter.hasNext()) {
iter.next().update(this);
}
}
@オーバーライド
public String getState() {
状態を返す。
}
@オーバーライド
public void changeState() {
this.state = 変更されました;
通知オブザーバー();
}
@オーバーライド
public void close() {
this.state = CLOSED;
通知オブザーバー();
}
}
インターフェイス IObserver {
void update(IObservable observalbe);
}
class Observer は IObserver {を実装します。
プライベート文字列名。
public Observer(文字列名) {
this.name = 名前;
}
@オーバーライド
public void update(IObservable observalbe) {
System.out.println(
String.format("%s は observalbe の変更を受け取りました。現在の observalbe の状態は %s",
名前、observalbe.getState()));
}
}
}
上記の実装は、監視されたオブジェクトをコールバック関数のパラメーターとして直接使用します。これは非常に洗練されていないため、単純なシナリオでは機能する可能性があります。
しかし、実際には、多くの場合、観察対象者には多くのイベントや状態があり、各観察者は異なるイベントや状態に興味があるかもしれません。あるいは、情報を隠す目的で、すべての観察者がすべての状態にアクセスできるようにする必要はありません。 Observable の内部。
このようにして、コードを次のバージョンに進化させ続けました。ここでは同時実行の問題については詳しく検討しませんでした。
次のようにコードをコピーします。
java.util.Collectionsをインポートします。
java.util.HashSet をインポートします。
java.util.Hashtableをインポートします。
java.util.Iteratorをインポートします。
java.util.Setをインポートします。
パブリック クラス MultiEventObserverPattern {
public static void main(String[] args) {
MultiEventObserverPattern meop = new MultiEventObserverPattern();
IObservable observable = meop.new Observable();
IObserver オブザーバーA = meop.new Observer("ObserverA");
IObserver オブザーバーB = meop.new Observer("ObserverB");
// 興味のあるイベントを登録します
observable.registerObserver(observable.getEventA(), observerA);
observable.registerObserver(observable.getEventB(), observerB);
// 観察された状態を変更します
observable.changeStateA();
observable.changeStateB();
}
インターフェイス IEvent {
voideventChange();
文字列 getState();
}
クラス EventA は IEvent を実装します {
private static Final String INITIALIZED = "初期化済み";
private static Final String PENDING = "保留中";
プライベート文字列の状態。
public EventA() {
this.state = 初期化済み;
}
@オーバーライド
public void eventChange() {
System.out.println("イベント A の変更");
this.state = 保留中;
}
@オーバーライド
public String toString() {
「イベントA」を返します;
}
@オーバーライド
public String getState() {
状態を返す。
}
}
クラス EventB は IEvent を実装します {
プライベート静的最終文字列 NEW = "新しい";
プライベート静的最終文字列 IDLE = "アイドル";
プライベート文字列の状態。
public EventB() {
this.state = NEW;
}
@オーバーライド
public void eventChange() {
System.out.println("イベントBの変更");
this.state = IDLE;
}
@オーバーライド
public String toString() {
「イベントB」を返します。
}
@オーバーライド
public String getState() {
状態を返す。
}
}
// 観察可能であり、サブジェクトと呼ばれることもあります
インターフェイス IObservable {
void registerObserver(IEvent イベント、IObserver オブザーバー);
void unregisterObserver(IEvent イベント、IObserver オブザーバー);
// イベントが発生したことをオブザーバーに通知します
void notificationObservers(IEvent イベント);
void changeStateA();
void changeStateB();
IEvent getEventA();
IEvent getEventB();
}
class Observable は IObservable {を実装します
プライベート IEvent イベント A;
プライベート IEvent イベント B;
private Hashtable<IEvent, Set<IObserver>>eventObserverMapping;
public Observable() {
これ(null);
}
// EvenObserverMapping によって渡された Set<IObserver> の一部が同期的に変更されていない場合、それに対してできることは何もありません。
public Observable(Hashtable<IEvent, Set<IObserver>>eventObserverMapping) {
if(eventObserverMapping == null) {
eventObserverMapping = new Hashtable<IEvent, Set<IObserver>> ();
}
this.eventObserverMapping = new Hashtable<IEvent, Set<IObserver>> ();
this.eventA = 新しい EventA();
this.eventB = 新しい EventB();
}
@オーバーライド
public void registerObserver(IEvent イベント, IObserver オブザーバー) {
Set<IObserver> オブザーバー =eventObserverMapping.get(event);
if(オブザーバー == null) {
オブザーバー = Collections.synchronizedSet(new HashSet<IObserver> ());
オブザーバー.add(オブザーバー);
eventObserverMapping.put(イベント, オブザーバー);
}
それ以外 {
オブザーバー.add(オブザーバー);
}
}
@オーバーライド
public void unregisterObserver(IEvent イベント, IObserver オブザーバー) {
Set<IObserver> オブザーバー =eventObserverMapping.get(event);
if(オブザーバー != null) {
オブザーバー.削除(オブザーバー);
}
}
@オーバーライド
public void NoticeObservers(IEvent イベント) {
Set<IObserver> オブザーバー =eventObserverMapping.get(event);
if(observers != null && observers.size() > 0) {
Iterator<IObserver> iter = observers.iterator();
while(iter.hasNext()) {
iter.next().update(event);
}
}
}
@オーバーライド
public void changeStateA() {
// 状態 A を変更するとイベント A がトリガーされます
イベントA.eventChange();
通知オブザーバー(イベントA);
}
@オーバーライド
public void changeStateB() {
// 状態 B を変更するとイベント B がトリガーされます
イベントB.eventChange();
通知オブザーバー(イベントB);
}
@オーバーライド
public IEvent getEventA() {
イベントAを返します。
}
@オーバーライド
public IEvent getEventB() {
イベントBを返します。
}
}
インターフェイス IObserver {
void update(IEvent イベント);
}
class Observer は IObserver {を実装します。
プライベート文字列名。
public Observer(文字列名) {
this.name = 名前;
}
@オーバーライド
public void update(IEvent イベント) {
System.out.println(
String.format("%s は %s の変更を受信しました。現在の監視の状態は %s",
名前、イベント、event.getState()));
}
}
}
完璧に見えますが、まだ完璧ではありません。イベントは Observer クラスのプロパティとしてハードコーディングされているためです。このように、イベント タイプはコンパイル時に決定されます。新しいイベント タイプを追加する場合は、IObservable インターフェイスと Observable クラスを変更する必要があり、柔軟性が大幅に低下します。
これは、オブザーバーがこれらの特定のイベントに結合されているのと同等です。では、この制限をどのように破るのでしょうか?
答えは、新しいコンポーネントを導入し、そのコンポーネントがイベント、オブザーバー、および監視対象オブジェクト間の関係を管理できるようにすることです。イベントが発生すると、そのコンポーネントはオブザーバーのコールバック関数も呼び出すようになります。これも一種の切り離しであり、Spring の IOC コンテナに似ています。
具体的な実装については、Guava EventBus がかなりうまく機能していると思います。先ほど述べたリンクを参照してください。
PS: この投稿は Guava EventBus の宣伝ではありませんが、私自身のアイデアは段階的に進められており、徐々に Guava EventBus の設計アイデアと一致していきます。
引き続き、オブザーバー パターンを実装する JDK 標準クラスの例を見て、そのソース コードの実装を分析してみましょう。観察する必要があるのは、Observable クラスと Observer インターフェイスだけです。
JDK標準クラスはオブザーバーパターンを実装します
次のようにコードをコピーします。
java.util.Observableをインポートします。
java.util.Observerをインポートします。
/**
* java.util パッケージの標準クラスを使用してオブザーバー パターンを実装します。
* @author は
*
*/
パブリック クラス JDKObserverDemo {
public static void main(String[] args) {
JDKObserverDemo jod = new JDKObserverDemo();
// オブザーバー
MyObservable myObservable = jod.new MyObservable("hello");
// オブザーバー
オブザーバー myObserver = jod.new MyObserver();
// 登録する
myObservable.addObserver(myObserver);
// 観察された状態を変更し、オブザーバーのコールバック関数をトリガーします
myObservable.setValue("意志");
}
class MyObservable extends Observable {
private String watchValue // 観測値;
public MyObservable(String WatchedValue) {
this.watchedValue = 監視された値;
}
public void setValue(String newValue) {
if(!watchedValue.equals(newValue)) {
監視された値 = 新しい値;
setChanged();
通知オブザーバー(newValue);
}
}
@オーバーライド
public String toString() {
"MyObservable" を返します。
}
}
クラス MyObserver は Observer {を実装します
@オーバーライド
public void update(Observable o, Object arg) {
System.out.println(o + " の状態が変更されました。引数は: " + arg);
}
}
}
JDK 標準ライブラリの Observer と Observable の実装を見てみると、非常に単純なので、これ以上は言いません。
以下は Quartz でのリスナー実装です。
QuartzScheduler リスナー
次のようにコードをコピーします。
java.util.ArrayListをインポートします。
java.util.Dateをインポートします。
java.util.Listをインポートします。
/**
※クォーツコアクラス、Observable(観測可能)と同等
* @author は
*
*/
パブリック クラス QuartzScheduler {
private ArrayList<SchedulerListener> InternalSchedulerListeners = new ArrayList<SchedulerListener>(10);
//private ArrayList<JobListener> interanlJobListeners = new ArrayList<JobListener>() // Observable には複数のリスナー セットを含めることができます。
public Date スケジュールジョブ(トリガートリガー) {
if(トリガー == null) {
null を返します。
}
System.out.println("ジョブのスケジュール、トリガー: " + トリガー);
NoticeSchedulerListenersScheduled(トリガー);
新しい Date() を返します。
}
public void unScheduleJob(トリガートリガー) {
if(トリガー == null) {
戻る;
}
System.out.println("ジョブのスケジュールを解除、トリガー: " + トリガー);
NoticeShedulerListenerUnScheduled(トリガー);
}
//SchedulerListenerを登録する
public void addInternalSchedulerListener(SchedulerListener スケジューラーリスナー) {
同期済み (internalSchedulerListeners) {
InternalSchedulerListeners.add(schedulerListener);
}
}
// SchedulerListener を削除します
public boolean RemoveInternalSchedulerListener(SchedulerListener スケジューラリスナー) {
同期済み (internalSchedulerListeners) {
戻りinternalSchedulerListeners.remove(schedulerListener);
}
}
public List<SchedulerListener> getInternalSchedulerListeners() {
同期済み (internalSchedulerListeners) {
return java.util.Collections.unmodifiableList(new ArrayList<SchedulerListener>(internalSchedulerListeners));
}
}
public void NoticeSchedulerListenersScheduled(Trigger トリガー) {
for(SchedulerListener リスナー: getInternalSchedulerListeners()) {
リスナー.jobScheduled(トリガー);
}
}
public void NoticeShedulerListenerUnScheduled(Trigger トリガー) {
for(SchedulerListener リスナー: getInternalSchedulerListeners()) {
listener.jobUnScheduled(トリガー);
}
}
}
スケジューラーリスナー
次のようにコードをコピーします。
// リスニング インターフェイス、コールバック関数、クライアントはモニタリングの登録時にコールバック関数の実装を提供する必要があります
パブリック インターフェイス SchedulerListener {
void jobScheduled(トリガートリガー);
void jobUnScheduled(トリガートリガー);
}
トリガー
次のようにコードをコピーします。
//トリガー
パブリッククラストリガー{
プライベート文字列トリガーキー;
プライベート文字列トリガー名;
public Trigger(String トリガーキー, String トリガー名) {
this.triggerKey = トリガーキー;
this.triggerName = トリガー名;
}
public String getTriggerKey() {
トリガーキーを返します。
}
public void setTriggerKey(String TriggerKey) {
this.triggerKey = トリガーキー;
}
public String getTriggerName() {
トリガー名を返します。
}
public void setTriggerName(String トリガー名) {
this.triggerName = トリガー名;
}
public String toString() {
return String.format("{トリガーキー: %s, トリガー名: %s}", トリガーキー, トリガー名);
}
}
テスト
次のようにコードをコピーします。
パブリック クラス テスト {
public static void main(String[] args) {
QuartzScheduler qs = new QuartzScheduler();
SchedulerListener リスナー A = new SchedulerListener() {
@オーバーライド
public void jobUnScheduled(トリガートリガー) {
System.out.println("listenerA ジョブがスケジュールされていません: " +trigger.getTriggerName());
}
@オーバーライド
public void jobScheduled(トリガートリガー) {
System.out.println("listenerA スケジュールされたジョブ: " +trigger.getTriggerName());
}
};
SchedulerListener リスナーB = new SchedulerListener() {
@オーバーライド
public void jobUnScheduled(トリガートリガー) {
System.out.println("listenerB ジョブがスケジュールされていません: " +trigger.getTriggerName());
}
@オーバーライド
public void jobScheduled(トリガートリガー) {
System.out.println("listenerB のスケジュールされたジョブ: " +trigger.getTriggerName());
}
};
//スケジューラーリスナーを登録
qs.addInternalSchedulerListener(listenerA);
qs.addInternalSchedulerListener(listenerB);
トリガーtriggerA = new Trigger("Key1", "triggerA");
トリガーtriggerB = new Trigger("Key2", "triggerB");
qs.scheduleJob(triggerA);
qs.scheduleJob(triggerB);
qs.unScheduleJob(triggerA);
}
}