現実の世界では、多くのオブジェクトはどこオブジェクトの変更の動作も変更され、他のオブジェクトの振る舞いの一つ以上になることがあり、独立していません。例えば、商品価格の価格は幸せ、悲しい、消費者、いくつかの企業につながるとき、私たちは交差点に運転したときにも、赤色光、緑色光がラインを越えてくる、停止します。こうした観客と株価や天気予報、泥棒と警察や他の投資家、公共のマイクロチャネル番号とマイクロチャネルのユーザー、気象局など多くのそのような例があります。
ソフトウェアの世界で同じように、例えば、Excelでデータや折れ線グラフ、円グラフ、棒グラフとの関係、モデルとMVCモードの表示との関係、イベントモデルのイベント・ソースとイベントハンドラ。Observerパターンは非常に簡単である場合には、これらのすべては、実装します。
モデルの定義と特性
定義された観察者(観察)モード:オブジェクトの状態が変化し、それに依存するすべてのオブジェクトが自動的に通知され、更新されたオブジェクトのうち多くの依存関係の存在を指します。モデル、モデル購読- -このモードは、時には公開と呼ばれる表示モードを、そのオブジェクトの行動パターンです。
オブザーバーパターンは、オブジェクトの行動パターンであり、その主な利点は次の通りです。
- 両者のオブジェクトと観察者、抽象的結合の間の結合を減少させます。
- 当社は、対象と観察者の間でトリガ機構を設定しました。
その主な欠点は次の通り。
- 対象と観察者との間の依存関係が完全に除去されず、循環参照があってもよいです。
- オブジェクトの多くのオブザーバーは、会議通知は多くの時間を費やす場合は、プログラムの効率に影響を与えます。
アーキテクチャと実装モデル
オブザーバーパターンを実装するオブジェクト指向設計の原則に違反して、それらの間の密結合を維持する特定のターゲットオーディエンスと特定のオブザーバーオブジェクト間で直接呼び出すことができないときに注意を払う必要があります。
1.構造モデル
オブザーバ・モードの主な役割は次の通りです。
- 抽象トピック(主題)の役割:また、抽象オブジェクトクラスとして知られている、すべてのオブザーバのビューアオブジェクト、削除オブザーバオブジェクト・メソッド、抽象メソッドおよび通知を保持するための集約と増加クラスを提供します。
- 特定のトピック(コンクリート件名)役割:また、その実装通知方法の抽象的な目標を、内部状態の特定のテーマの変更、登録済みのすべてのオブザーバーオブジェクトに通知し、特定のターゲットクラスとして知られています。
- 抽象観測者(オブザーバー)役割:それは受け取る変更通知、特定のテーマが呼び出され、更新彼の抽象メソッドが含まれ、抽象クラスまたはインタフェースです。
- 特定の観測者(コンクリートオブザーバー)の役割:変更通知の目標を取得するときに自分のステータスを更新するために実装される抽象オブザーバーで定義された抽象メソッド。
図1に示したオブザーバーパターン構成図。
実現の2モード
Observerパターンのコードは次のとおりです。
package observer;
import java.util.*;
public class ObserverPattern
{
public static void main(String[] args)
{
Subject subject=new ConcreteSubject();
Observer obs1=new ConcreteObserver1();
Observer obs2=new ConcreteObserver2();
subject.add(obs1);
subject.add(obs2);
subject.notifyObserver();
}
}
//抽象目标
abstract class Subject
{
protected List<Observer> observers=new ArrayList<Observer>();
//增加观察者方法
public void add(Observer observer)
{
observers.add(observer);
}
//删除观察者方法
public void remove(Observer observer)
{
observers.remove(observer);
}
public abstract void notifyObserver(); //通知观察者方法
}
//具体目标
class ConcreteSubject extends Subject
{
public void notifyObserver()
{
System.out.println("具体目标发生改变...");
System.out.println("--------------");
for(Object obs:observers)
{
((Observer)obs).response();
}
}
}
//抽象观察者
interface Observer
{
void response(); //反应
}
//具体观察者1
class ConcreteObserver1 implements Observer
{
public void response()
{
System.out.println("具体观察者1作出反应!");
}
}
//具体观察者1
class ConcreteObserver2 implements Observer
{
public void response()
{
System.out.println("具体观察者2作出反应!");
}
}
次のようにプログラムの結果は以下のとおりです。
具体目标发生改变...
--------------
具体观察者1作出反应!
具体观察者2作出反应!
応用例のモード
[実施例1] Observerパターンは、輸入会社輸入製品コストや輸出企業の輸出製品と会社の収益の感謝や減価償却費の影響「為替レート」のマージンを分析するためのプログラムを設計使用。
分析:、輸入企業が輸入品と利益率の改善のコストを削減すると、「為替レート」の感謝、同社の輸出製品は、収益と減少し利益率をエクスポートし、「為替レート」切り下げ、輸入会社輸入製品とアップグレードのコスト低利益率は、輸出企業は、収益と利益率の改善を強化するために製品を輸出します。
ここでは、為替レート(レート)ターゲットクラスは、保存された観測者(会社)のリストおよび追加/削除を観測方法、および為替レートの変動(int型の数)に関連する抽象メソッドの変更が含まれている抽象クラスでだ、と人民元の為替レート(RMBrate )為替レートは、関連会社によって変更される、すなわち、親クラス(INT番号)方式の変更を実装する特定の目的のクラスを、(会社)は、抽象メソッドに関連する交換反応を定義する抽象クラスオブザーバ、あります応答(INTの数);輸入会社(ImportCompany)クラスと出口コーポレーション(ExportCompany)視聴者のクラスは、親応答(INT番号)を実装する具象クラスである方法、即ち、それらは為替レートの変更通知を受け取りますそれに応じて。図2は、構成図です。
コードは以下の通りであります:
package observer;
import java.util.*;
public class RMBrateTest
{
public static void main(String[] args)
{
Rate rate=new RMBrate();
Company watcher1=new ImportCompany();
Company watcher2=new ExportCompany();
rate.add(watcher1);
rate.add(watcher2);
rate.change(10);
rate.change(-9);
}
}
//抽象目标:汇率
abstract class Rate
{
protected List<Company> companys=new ArrayList<Company>();
//增加观察者方法
public void add(Company company)
{
companys.add(company);
}
//删除观察者方法
public void remove(Company company)
{
companys.remove(company);
}
public abstract void change(int number);
}
//具体目标:人民币汇率
class RMBrate extends Rate
{
public void change(int number)
{
for(Company obs:companys)
{
((Company)obs).response(number);
}
}
}
//抽象观察者:公司
interface Company
{
void response(int number);
}
//具体观察者1:进口公司
class ImportCompany implements Company
{
public void response(int number)
{
if(number>0)
{
System.out.println("人民币汇率升值"+number+"个基点,降低了进口产品成本,提升了进口公司利润率。");
}
else if(number<0)
{
System.out.println("人民币汇率贬值"+(-number)+"个基点,提升了进口产品成本,降低了进口公司利润率。");
}
}
}
//具体观察者2:出口公司
class ExportCompany implements Company
{
public void response(int number)
{
if(number>0)
{
System.out.println("人民币汇率升值"+number+"个基点,降低了出口产品收入,降低了出口公司的销售利润率。");
}
else if(number<0)
{
System.out.println("人民币汇率贬值"+(-number)+"个基点,提升了出口产品收入,提升了出口公司的销售利润率。");
}
}
}
次のようにプログラムの結果は以下のとおりです。
人民币汇率升值10个基点,降低了进口产品成本,提升了进口公司利润率。
人民币汇率升值10个基点,降低了出口产品收入,降低了出口公司的销售利润率。
人民币汇率贬值9个基点,提升了进口产品成本,降低了进口公司利润率。
人民币汇率贬值9个基点,提升了出口产品收入,提升了出口公司的销售利润率。
ソフトウェアの同時実行及びイベント処理プログラムの設計の最も頻繁に使用される形態でオブザーバーパターン、形状のすべてのコンポーネントがターゲット・オブジェクトであることを、「イベントソース」であり、オブジェクトはイベントハンドラクラスの特定の観察でありますオブジェクト人々 。Windowsのイベント処理モデル「作品の例として、学校の鐘のイベントハンドラは、以下。
【例2】学校の鐘のオブザーバーパターンのデザインを使用してイベントハンドラを。
分析:この例では、学校「ベル」がイベントソースとターゲットである、「教師」と「生徒」は、特定のイベントリスナーとオブザーバーである、「ベル」イベントクラスです。生徒と教師は、結合事象と呼ばれる学校の鐘、に注意を払うだろう、学校教育の領域に来た、授業時間やベルの音をトリガーする授業時間の後に、その後、「ベル」イベントを生成するとき、生徒と教師の鐘を聞きました彼らは、イベント処理と呼ばれる学校やクラスを、開始します。この例はよく利用オブザーバーパターン、図3に示すイベントモデル校の着信音に適しています。
今、「オブザーバーモード」でイベント処理モデルを実現しています。まず、型(クラスリング/クラスリング)着信音を記録リンギングイベント(RingEvent)クラスを定義します。学校の鐘の再定義イベントソースである(BellEventSource)クラス、客観オブザーバークラス、リスナーのコンテナリスナーが含まれている、あなたは、リスナー(学生や教師)に結合することができ、およびトーンのイベントを生成し、すべてのリスナーに通知する方法があります;そして、抽象オブザーバーあるサウンドイベントリスナー(BellEventListener)クラスを定義、それを着メロは、イベントハンドラメソッドheardBell(RingEvent電子)が含まれ;そして最後に、イベントリスナーであるクラスの先生(TeachEventListener)の定義と学生カテゴリ(StuEventListener)は、ベルがクラスにまたはクラスの後に行くと聞いて、特定の観測者、です。図4は、学校の鐘のイベントハンドラの構造を示しています。
コードは以下の通りであります:
package observer;
import java.util.*;
public class BellEventTest
{
public static void main(String[] args)
{
BellEventSource bell=new BellEventSource(); //铃(事件源)
bell.addPersonListener(new TeachEventListener()); //注册监听器(老师)
bell.addPersonListener(new StuEventListener()); //注册监听器(学生)
bell.ring(true); //打上课铃声
System.out.println("------------");
bell.ring(false); //打下课铃声
}
}
//铃声事件类:用于封装事件源及一些与事件相关的参数
class RingEvent extends EventObject
{
private static final long serialVersionUID=1L;
private boolean sound; //true表示上课铃声,false表示下课铃声
public RingEvent(Object source,boolean sound)
{
super(source);
this.sound=sound;
}
public void setSound(boolean sound)
{
this.sound=sound;
}
public boolean getSound()
{
return this.sound;
}
}
//目标类:事件源,铃
class BellEventSource
{
private List<BellEventListener> listener; //监听器容器
public BellEventSource()
{
listener=new ArrayList<BellEventListener>();
}
//给事件源绑定监听器
public void addPersonListener(BellEventListener ren)
{
listener.add(ren);
}
//事件触发器:敲钟,当铃声sound的值发生变化时,触发事件。
public void ring(boolean sound)
{
String type=sound?"上课铃":"下课铃";
System.out.println(type+"响!");
RingEvent event=new RingEvent(this, sound);
notifies(event); //通知注册在该事件源上的所有监听器
}
//当事件发生时,通知绑定在该事件源上的所有监听器做出反应(调用事件处理方法)
protected void notifies(RingEvent e)
{
BellEventListener ren=null;
Iterator<BellEventListener> iterator=listener.iterator();
while(iterator.hasNext())
{
ren=iterator.next();
ren.heardBell(e);
}
}
}
//抽象观察者类:铃声事件监听器
interface BellEventListener extends EventListener
{
//事件处理方法,听到铃声
public void heardBell(RingEvent e);
}
//具体观察者类:老师事件监听器
class TeachEventListener implements BellEventListener
{
public void heardBell(RingEvent e)
{
if(e.getSound())
{
System.out.println("老师上课了...");
}
else
{
System.out.println("老师下课了...");
}
}
}
//具体观察者类:学生事件监听器
class StuEventListener implements BellEventListener
{
public void heardBell(RingEvent e)
{
if(e.getSound())
{
System.out.println("同学们,上课了...");
}
else
{
System.out.println("同学们,下课了...");
}
}
}
次のようにプログラムの結果は以下のとおりです。
上课铃响!
老师上课了...
同学们,上课了...
------------
下课铃响!
老师下课了...
同学们,下课了...
シーンモードの応用
前述のオブザーバーパターン分析およびアプリケーションによって見られる次のような状況のために。
- オブジェクト間の多くの関係は、オブジェクトの状態の変化は、他のオブジェクトに影響を与えます。
- 抽象モデルが他方に依存する一の態様その2つの側面を有する場合、それらは独立して変化し、再利用することができるように、これらの両方は、別個のオブジェクトにカプセル化されてもよいです。
拡張モード
、Javaではクラスとjava.util.Observable java.util.Observerインタフェース定義オブザーバーパターンにより、限り、それらがサブクラスを達成するようにオブザーバーパターンインスタンスを書き込むことができます。
1.観察可能なクラス
観測可能なクラスは抽象クラスの目標である、それはすべてのオブザーバーが通知されるようにオブジェクトを保持するために使用ベクトルベクトルを持っている、のは、その最も重要な3つのメソッドを紹介しましょう。
- 空addObserver(オブザーバー0)方法:ベクトルに新しいオブジェクトを追加するためのビューア。
- 空notifyObservers(オブジェクトの引数)メソッド:コールアップデートすべてのオブザーバオブジェクトベクトル。データの変更ことを通知する方法。通常、観察者の最初のベクトルの後の添加を通知します。
- ボイドsetChange()メソッド:ターゲットオブジェクトの変更を示す、ブーリアン内部フラグを設定するために使用されます。それがtrueの場合、notifyObservers()ビューアを通知します。
2.オブザーバーインターフェース
オブザーバインタフェースは、視聴者が通知され、対象物におけるモニターの変更がターゲット・オブジェクトが変更された抽象ビューア、であり、ボイド更新(観測O、オブジェクト引数呼び出し ) 方法、対応する作業。
クラスとオブザーバーパターンインスタンス原油先物インタフェース観測オブザーバを使用した[実施例3]。
分析:原油価格、悲しい短辺、及びよりFangju興、石油価格が下落、Fangju興、マルチ悲しいを空にする。本実施例では、抽象目標は、(観測)クラスは、サブクラスは、ときに、直接的に、すなわち、具体的な対象クラスである粗(OilFutures)クラス、クラスが定義されているSetPriCe(フロート価格)メソッドを定義することができ、Javaで定義され粗データ呼親クラスは、すべての観察者に通知するnotifyObservers(オブジェクト引数)を変更する。本実施例では、観察者(観察者)の抽象インターフェースは、Javaで定義されている限り、サブクラスが定義されているように、すなわち、特定の観察カテゴリ別の方法でもよく、実装更新(オブジェクト引数が観測O、)(マルチパーティベースおよび宇宙ベースのブルベアを含みます)。図5の構成を図。
コードは以下の通りであります:
package observer;
import java.util.Observer;
import java.util.Observable;
public class CrudeOilFutures
{
public static void main(String[] args)
{
OilFutures oil=new OilFutures();
Observer bull=new Bull(); //多方
Observer bear=new Bear(); //空方
oil.addObserver(bull);
oil.addObserver(bear);
oil.setPrice(10);
oil.setPrice(-8);
}
}
//具体目标类:原油期货
class OilFutures extends Observable
{
private float price;
public float getPrice()
{
return this.price;
}
public void setPrice(float price)
{
super.setChanged() ; //设置内部标志位,注明数据发生变化
super.notifyObservers(price); //通知观察者价格改变了
this.price=price ;
}
}
//具体观察者类:多方
class Bull implements Observer
{
public void update(Observable o,Object arg)
{
Float price=((Float)arg).floatValue();
if(price>0)
{
System.out.println("油价上涨"+price+"元,多方高兴了!");
}
else
{
System.out.println("油价下跌"+(-price)+"元,多方伤心了!");
}
}
}
//具体观察者类:空方
class Bear implements Observer
{
public void update(Observable o,Object arg)
{
Float price=((Float)arg).floatValue();
if(price>0)
{
System.out.println("油价上涨"+price+"元,空方伤心了!");
}
else
{
System.out.println("油价下跌"+(-price)+"元,空方高兴了!");
}
}
}
次のようにプログラムの結果は以下のとおりです。
油价上涨10.0元,空方伤心了!
油价上涨10.0元,多方高兴了!
油价下跌8.0元,空方高兴了!
油价下跌8.0元,多方伤心了!