学習ノート---設計モードの観察者モード


転載:http://www.cnblogs.com/shitouer/archive/2011/09/02/2164048.html
Head Firstでは、次のようなシーンが表示されます.
お客様は、WheatherDataクラスが気象ステーションから気象情報(temperature,humidity,pressure and so on)を取得できるAppが必要です.これらの情報が変更されると、気象ステーションの3つの掲示板(CurrentConditionBulletin,StatisticsBulletin and ForecastBulletin、また、ユーザーはいつでも自分の掲示板を追加/削除/変更することができます)が更新されます.
お客様はWheatherDataのクラス図を示しています.
    
以上の説明とクラス図に関連して、以下のことが知られています.
    1. Getterで気象情報を得ることができます
    2. 気象情報が変更されると、measurementsChanged()メソッドを呼び出してすべての掲示板を更新します.
    3. 今は3つの掲示板が必要です
    4. Customerは自分の掲示板を定義できます
まず悪い実現を見てみましょう.
publicclass WeatherData {       
 
        publicvoid MeasurementsChanged()
        {
            floattemp = getTemperature(); 
            floathumidity = getHumidity(); 
            floatpressure = getPressure();
            currentConditionsDisplay.update(temp, humidity, pressure); 
            statisticsDisplay.update(temp, humidity, pressure);
            forecastDisplay.update(temp, humidity, pressure);
        }
}

?
どうしてよくないのですか.すでに知っているいくつかの設計原則から着手することができます.
    1. プログラムの変化する部分を探し出して、それを固定して不変の部分と隔離します
このシーンでは、布告欄のタイプと数が変化しますが、この悪い例では、布告欄のタイプと数を変更するには、WheatherDataというクラスを修正する必要があります.どのようにして掲示板の数や種類を勝手に変更できますが、WheatherDataクラスを変更しなくてもいいのでしょうか.
    2. インタフェースプログラミング、実装プログラミング
明らかに、statisticsDisplay、statisticsDisplay、forecastDisplayはすべて具体的な実装のプログラミングで、もし後で掲示板を修正するならば、すべてこのプログラムを修正しなければなりません.また、3つのメソッド(update()の名前とパラメータは同じで、1つの統一的なインタフェースは実行できますか?
新聞購読業務に基づいて、観察者モデルを簡単に理解することができます.
学习笔记 ---- 设计模式之观察者模式_第1张图片
オブザーバパターンクラス図:
    
    Subject
トピックインタフェースは,オブザーバー(Observable)であり,オブジェクトはこのインタフェースを用いてオブザーバーとして登録したり,自分をオブザーバーから削除したりする.各トピックには複数のオブザーバーがあります.
    ConcreteSubject
特定のトピックはトピックインタフェースを実装し、登録と取り消しに加えて、特定のトピックは、トピックの状態が変化したときにすべてのオブザーバーを実行するためのnotifyObservers()メソッドを実装します.特定のトピックには、ステータスを設定および取得する方法もあります.
    Observer
すべての潜在的なオブザーバーは、update()メソッドのみがトピックが変更されると呼び出されるオブザーバーインタフェースを実装する必要があります.
    ConcreteObserver
特定の観察者は、Observerインタフェースを実装した任意のクラスであってもよい.観察者は特定のトピックを登録し、更新を受信しなければならない.
基本原則:インタラクティブオブジェクト間の松結合設計のために努力する
オブザーバーモードの定義:オブザーバーモードは、オブジェクト間の一対のマルチ依存性を定義します.これにより、オブジェクトがステータスを変更すると、すべての依存者が通知を受け取り、自動的に更新されます.
観察者モードでは、一対多の関係はどこに現れますか?
このモードでは、トピックはステータスを持つオブジェクトであり、このステータスを制御することができます.つまり、「ステータス」を持つトピックです.
一方,観察者はこれらの状態を用いたが,これらの状態は彼らに属していない.複数の観察者が、テーマに頼ってテーマの状態がいつ変わったかを教えてくれます.
これにより、複数の「観察者」に対する「テーマ」の関係が生まれます.
松結合設計の威力はどこに現れますか?
2つのオブジェクトが緩やかに結合すると,彼らは依然として対話できるが,互いの詳細はよく分からない.オブザーバーモードは、トピックとオブザーバーを緩やかに結合させるオブジェクト設計を提供します.
     学习笔记 ---- 设计模式之观察者模式_第2张图片
次に、観察者パターンに基づいてWheatherStationのクラス図を作成します.
    
コードは次のとおりです.
  ISubject:
?
importorg.jpatterns.gof.ObserverPattern;
 
@ObserverPattern(
        comment="ISubject: Interface of Observer Pattern"
)
publicinterface ISubject {
    voidregisterObserver(IObserver o);
    voiddeleteObserver(IObserver o);
    voidnotifyObservers();
}
  IObserver:
?
importorg.jpatterns.gof.ObserverPattern;
 
@ObserverPattern(
        comment="IObserver: Interface of Observer Pattern"
)
publicinterface IObserver {
    voidupdate(floattemp, floathumidity, floatpressure);
}
     ISubject   WheatherData:
?
importjava.util.ArrayList;
 
importorg.jpatterns.gof.ObserverPattern;
 
@ObserverPattern(comment = "WheatherData: Concrete Subject of Observer Pattern")
publicclass WheatherData implementsISubject {
    privateArrayList<IObserver> observers;
    privatefloat temperature;
    privatefloat humidity;
    privatefloat pressure;
 
    publicWheatherData() {
        this.observers = newArrayList<IObserver>();
    }
 
    @Override
    publicvoid registerObserver(IObserver o) {
        observers.add(o);
    }
 
    @Override
    publicvoid deleteObserver(IObserver o) {
        if(observers.indexOf(o) >= 0) {
            observers.remove(o);
        }
    }
 
    @Override
    publicvoid notifyObservers() {
        for(inti = 0; i < observers.size(); i++) {
            IObserver observer = observers.get(i);
            observer.update(temperature, humidity, pressure);
        }
    }
 
    publicvoid measurementsChanged() {
        this.notifyObservers();
    }
 
    publicvoid setMeasurements(floattemperature, floathumidity, floatpressure) {
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        this.measurementsChanged();
    }
}
     IObserver     Bulletin:
?
publicclass CurrentConditionsBulletin implementsIObserver, IDisplayElement {
 
    privatefloat temperature;
    privatefloat humidity;
    privateISubject wheatherData;
 
    publicCurrentConditionsBulletin(ISubject wheatherData) {
        this.wheatherData = wheatherData;
        wheatherData.registerObserver(this);
    }
 
    @Override
    publicvoid update(floattemp, floathumidity, floatpressure) {
        this.temperature = temp;
        this.humidity = humidity;
        this.display();
    }
 
    @Override
    publicvoid display() {
        System.out.println("Current Conditions: " + this.temperature
                +"F Degrees and " + this.humidity + "% Humidity");
    }
}
       ,   run  :
?
publicclass WheatherStation {
 
    publicstatic void main(String[] args) {
        WheatherData wheatherData = newWheatherData();
        IObserver o1 = newCurrentConditionsBulletin(wheatherData);
        IObserver o2 = newStatisticsBulletin(wheatherData);
        IObserver o3 = newForecastBulletin(wheatherData);
        IObserver o4 = newCustomBulletin(wheatherData);//    
        wheatherData2.setMeasurements(20,20,20);
    }
 
}

注釈がたくさん省略されていますね.よく理解したいなら、HeadFirstを読むことをお勧めします.正直、本がいいですね.
実はjavaにはすでに観察者モードが内蔵されています.java.utilのObservable(クラス)とObserver(インタフェース).しかし、欠点は少なくない.例えば、プログラミングを実現するためではなく、インタフェースに対して、マルチコンビネーションを少なくするために継承する2つの原則に違反し、nofifyも順序に依存している.
オブザーバーモードのポイント:
オブザーバーは、オブジェクト間の1対多の関係を定義します.
トピックは、観察者を更新するために共通のインタフェースを使用します.
観察者と観察者との間には松結合方式が結合しており,観察者は観察者の詳細を知らず,観察者が観察者インタフェースを実現したことしか知らない.
このモードを使用すると、観察者からデータをプッシュまたはプルできます.
複数の観察者がいる場合、特定の通知順序に依存してはならない.
javaに注意してください.util.Observable実装上の問題.
必要ならば、自分のObservableを実現できます.
オブザーバモードの応用
オブザーバモードの利点
観察者と観察者の間には抽象的な結合がある.
完全なトリガチェーンを構築
オブザーバーモードの欠点
マルチレベルトリガの効率の問題
Javaのメッセージの通知はデフォルトで順番に実行され、オブザーバーのシェルが全体の効率に影響します.
オブザーバモードの使用シーン
分割可能な関連動作シーン
イベントマルチレベルトリガシーン
システム間メッセージ交換シーン