程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> Java設計模式之Observer模式

Java設計模式之Observer模式

編輯:關於JAVA

Observer模式也叫觀察者模式,是由GoF提出的23種軟件設計模式的一種。Observer模式是行為模式之一,它的作用是當一個對象的狀態發生變化時,能夠自動通知其他關聯對象,自動刷新對象狀態。

本文介紹設計模式中的(Observer)模式的概念,用法,以及實際應用中怎麼樣使用Observer模式進行開發。

Observer模式的概念

Observer模式是行為模式之一,它的作用是當一個對象的狀態發生變化時,能夠自動通知其他關聯對象,自動刷新對象狀態。

Observer模式提供給關聯對象一種同步通信的手段,使某個對象與依賴它的其他對象之間保持狀態同步。

Observer模式的典型應用

- 偵聽事件驅動程序設計中的外部事件

- 偵聽/監視某個對象的狀態變化

- 發布者/訂閱者(publisher/subscriber)模型中,當一個外部事件(新的產品,消息的出現等等)被觸發時,通知郵件列表中的訂閱者

Observer模式的優點

- 對象之間可以進行同步通信

- 可以同時通知一到多個關聯對象

- 對象之間的關系以松耦合的形式組合,互不依賴

Observer模式的結構

Observer模式的角色:

Subject(被觀察者)

被觀察的對象。當需要被觀察的狀態發生變化時,需要通知隊列中所有觀察者對象。Subject需要維持(添加,刪除,通知)一個觀察者對象的隊列列表。

ConcreteSubject

被觀察者的具體實現。包含一些基本的屬性狀態及其他操作。

Observer(觀察者)

接口或抽象類。當Subject的狀態發生變化時,Observer對象將通過一個callback函數得到通知。

ConcreteObserver

觀察者的具體實現。得到通知後將完成一些具體的業務邏輯處理。

JDK對Observer模式的支持

JDK提供了對observer設計模式的支持:

- 通過java.util.Observable類扮演Subject角色,一個類只需通過繼承java.util.Observable類便可擔當ConcreteSubject角色;

- 通過java.util.Observer接口扮演Observer角色,一個類只需實現java.util.Observer接口便可擔當ConcreteObserver角色。

- java.util.Observable的實現類通過調用setChanged()方法以及notifyObservers(Object)方法便可簡單地通知Observer。

當然,我們也可以不使用JDK提供的類與接口而自己實現Observer模式。

Observer模式的應用范例

下面,我們使用JDK提供的接口與類來實現一個Observer模式用來模擬新聞訂閱操作:

當一個新聞被發表時,系統一方面需要通知管理者審閱;另一方面需要通知訂閱者。

文件一覽:

Client

測試類。

NewsPublisher

相當於ConcreteSubject角色。該類繼承相當於Subject角色的java.util.Observable類。

SubscriberObserver

相當於ConcreteObserver角色。該類實現了相當於Observer角色的java.util.Observer接口。當NewsPublisher對象發生變化時得到通知,並向訂閱者發送訂閱郵件。

ManagerObserver

相當於ConcreteObserver角色。該類實現了相當於Observer角色的java.util.Observer接口。當NewsPublisher對象發生變化時得到通知,並向管理者發送消息郵件。

News

封裝了新聞數據的類,與Observer模式無直接關系。

代碼:

import java.util.Observable;
import java.util.Observer;
public class Client {
  /**
   * Test Observer Pattern
   * --
   *
   */
  public static void main(String[] args) {
    NewsPublisher publisher = new NewsPublisher();
    //添加觀察者對象
    publisher.addObserver(new SubscriberObserver());
    publisher.addObserver(new ManagerObserver());

    //發布新聞,觸發通知事件
    publisher.publishNews("Hello news", "news body");
  }
}
/**
* Subject ROLE
* NewsPublisher: news publisher
*
*/
class NewsPublisher extends Observable {
  public void publishNews(String newsTitle, String newsBody) {
    News news = new News(newsTitle, newsBody);
    setChanged();    //通過setChanged()方法標明對象的狀態已發生變化

    System.out.println("News published:" + newsTitle);
    this.notifyObservers(news);  //通知各Observer,並發送一個名為news對象的消息

    //other process ... such as save news to database
  }
}
/**
* Observer ROLE
*
*/
class SubscriberObserver implements Observer {

  public void update(Observable observee, Object param) {
    if (param instanceof News) {
      mail2Subscriber((News)param);
    }
  }

  private void mail2Subscriber(News news) {
    System.out.println("Mail to subscriber. A news published with title:" + news.getTitle());
  }
}
/**
* Observer ROLE
*
*/
class ManagerObserver implements Observer {

  public void update(Observable observee, Object param) {
    if (param instanceof News) {
      mail2Manager((News)param);
    }
  }

  private void mail2Manager(News news) {
    System.out.println("Mail to Manager. A news published with title:" + news.getTitle());
  }
}
//data entity
class News {
  private String title;
  private String body;

  public News(String title, String body) {
    this.title = title;
    this.body = body;
  }

  public String getBody() {
    return body;
  }
  public void setBody(String body) {
    this.body = body;
  }
  public String getTitle() {
    return title;
  }
  public void setTitle(String title) {
    this.title = title;
  }
}

執行Client,輸出結果:

C:Observer>javac *.java
C:Observer>java Client
News published:Hello news
Mail to Manager. A news published with title:Hello news
Mail to subscriber. A news published with title:Hello news
C:Observer>

NewsPublisher通過setChanged()與notifyObservers(Object)方法通知Observer對象SubscriberObserver與ManagerObserver。

不適用jdk支持的情況下的代碼

Observer模式的好處是:它解除了觀察者和目標之間的耦合關系。目標不需要知道它的觀察者的任何信息。相反,目標只是允許觀察者訂閱事件。當目標產生一個事件時,它簡單地將事件傳給每一個觀察者。

看看下面的Java示例:

public interface Subject {
   public void addObserver( Observer o );
   public void removeObserver( Observer o );
}

上面的代碼中,Subject接口定義了兩個方法(method),每個Subject都必須實現它們,以使Observer可以在Subject中增加或刪除自身。

public interface Observer {
   public void update( Subject o );
}

Observer接口(如上)列出了一個方法(method),每個Observer都必須實現它,以使Subject可以發送更新消息給Observer。

下面看看Subject的一個簡單的實現--IntegerDataBag:

import java.util.ArrayList;
import java.util.Iterator;

public class IntegerDataBag implements Subject {

   private ArrayList list = new ArrayList();
   private ArrayList observers = new ArrayList();

   public void add( Integer i ) {
      list.add( i );
      notifyObservers();
   }

   public Iterator iterator() {
      return list.iterator();
   }

   public Integer remove( int index ) {
      if( index < list.size() ) {
         Integer i = (Integer) list.remove( index );
         notifyObservers();
         return i;
      }
      return null;
   }

   public void addObserver( Observer o ) {
      observers.add( o );
   }

   public void removeObserver( Observer o ) {
      observers.remove( o );
   }

   private void notifyObservers() {
      // loop through and notify each observer
      Iterator i = observers.iterator();
      while( i.hasNext() ) {
         Observer o = ( Observer ) i.next();
         o.update( this );
      }
   }
}

IntegerDataBag適用於使用Integer的場合。IntegerDataBag也允許Observer增加和刪除它們自身。

再看看兩個Observer的實現--IntegerAdder和IntegerPrinter:

import java.util.Iterator;

public class IntegerAdder implements Observer {

   private IntegerDataBag bag;

   public IntegerAdder( IntegerDataBag bag ) {
      this.bag = bag;       
      bag.addObserver( this );
   }

   public void update( Subject o ) {
      if( o == bag ) {
         System.out.println( "The contents of the IntegerDataBag have changed." );
         int counter = 0;
         Iterator i = bag.iterator();
         while( i.hasNext() ) {
            Integer integer = ( Integer ) i.next();
            counter+=integer.intValue();
         }
         System.out.println( "The new sum of the integers is: " + counter );
      }
   }

}

import java.util.Iterator;

public class IntegerPrinter implements Observer {

   private IntegerDataBag bag;

   public IntegerPrinter( IntegerDataBag bag ) {
      this.bag = bag;       
      bag.addObserver( this );
   }

   public void update( Subject o ) {
      if( o == bag ) {
         System.out.println( "The contents of the IntegerDataBag have changed." );
         System.out.println( "The new contents of the IntegerDataBag contains:" );
         Iterator i = bag.iterator();
         while( i.hasNext() ) {
            System.out.println( i.next() );
         }
      }
   }

}

IntegerAdder和IntegerPrinter將自己作為觀察者增加到IntegerDataBag。當IntegerAdder接收到一條更新消息時,它先統計bag中的總數,然後顯示結果。同樣,當IntegerPrinter接收到一條更新消息時,它打印出bag中的 Interger。

下面是一個簡單的main(),它使用了上面的幾個類:

public class Driver {
   public static void main( String [] args ) {
      Integer i1 = new Integer( 1 ); Integer i2 = new Integer( 2 );
      Integer i3 = new Integer( 3 ); Integer i4 = new Integer( 4 );
      Integer i5 = new Integer( 5 ); Integer i6 = new Integer( 6 );
      Integer i7 = new Integer( 7 ); Integer i8 = new Integer( 8 );
      Integer i9 = new Integer( 9 );

      IntegerDataBag bag = new IntegerDataBag();
      bag.add( i1 ); bag.add( i2 ); bag.add( i3 ); bag.add( i4 );
      bag.add( i5 ); bag.add( i6 ); bag.add( i7 ); bag.add( i8 );

      IntegerAdder adder = new IntegerAdder( bag );
      IntegerPrinter printer = new IntegerPrinter( bag );

      // adder and printer add themselves to the bag

      System.out.println( "About to add another integer to the bag:" );
      bag.add( i9 );
      System.out.println("");
      System.out.println("About to remove an integer from the bag:");
      bag.remove( 0 );
   }
}

運行main,你將看到:

c:javaworldjava Driver
About to add another integer to the bag:
The contents of the IntegerDataBag have changed.
The new sum of the intergers is: 45
The contents of the IntegerDataBag have changed.
The new contents of the IntegerDataBag contains:
1
2
3
4
5
6
7
8
9

About to remove an integer from the bag:
The contents of the IntegerDataBag have changed.
The new sum of the intergers is: 44
The contents of the IntegerDataBag have changed.
The new contents of the IntegerDataBag contains:
2
3
4
5
6
7
8
9

IntegerDataBag/IntegerAdder/IntegerPrinter是應用Observer模式的一個很簡單的例子。Java 本身有大量使用Observer模式的例子:AWT/Swing事件模型,還有java.util.Observer和 java.util.Observable接口等,都是很好的例子。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved