觀察者模式

簡介

1.學習本篇博文,咱們知道在什麼場景下使用觀察者模式。
2.觀察者模式的優缺點。
3.觀察者模式給咱們在從此開發中什麼思想。java

場景

某家科技公司目前在開發一個項目,設計小組須要上報項目的進度給部門經理,主要有兩個模塊更新原有的業務模塊進度和添加新業務的模塊完成進度。
那麼部門經理須要什麼途徑能最快的獲得進度的信息呢?或者多是項目總監也想參與,去獲取到最新的進展狀況呢?咱們改如何去考慮這個業務呢?git

不少時候咱們就會想到繼承去解決這一狀況,畢竟OO編寫思想時刻影響這一咱們,可是若是某天項目經理出差了,他不想看項目進度了,那咱們又改怎麼辦呢?github

咱們能不能就是設計一個業務,讓能想知道該進度的人,無論何時,只要有開發者上報進度的時候就一下他就獲得進度的信息,而他無需去關係這個過程。編程

你是否能想到合適的解決方案呢?設計模式

答案就在下文中,你準備好了嗎?ide

問題

什麼是觀察者模式?

觀察者模式定義一系列對象之間的一對多關係,當一個對象改變、更新狀態時,依賴它的都會收到通知改變或者更新。函數

爲何須要觀察者模式?

從定義中咱們能夠知道觀察者模式當對象改變時,其餘依賴的對象都會收到改變信息的狀態。學習

從本例分析項目經理想知道進度狀況,他只須要綁定進度,他就能夠知道進度信息了,而無需關心如何操做,若是再增長一個想知道進度信息老闆呢?也很容易,也讓老闆綁定進度信息數據就行了,不想知道的時候就解除綁定,就不在獲取進度信息了。測試

因此在本案例場景中,觀察者是咱們這個場景很是合適的設計。this

如何實現觀察者模式?

自定義觀察者模式

實現以下

咱們先來看一下這個UML類圖進行分析

observer.png

具體實現步驟

1.構造一個主題Subject或者是一個被觀察者Observeable,這是一個接口或者是抽象類

public interface Subject {
   //註冊觀察者
   void registerObserver(Observer observe);
   //解除綁定觀察者
   void unRegisterObserver(Observer observe);
   //更新數據
   void notifyObservers();
 }

2.構建一個被觀察者實現該主題接口如本例的 DevelopmentProgressData.class,這裏是進度信息數據
在registerObserver(Observer o);//方法中將觀察者添加到註冊列表中
在unRegisterObserve(Observer o);//刪除觀察者

public class DevelopmentProgressData implements Subject {
 @Override
   public void registerObserver(Observer observer) {
       //將觀察者添加到列表中
       arrayObserve.add(observer);
   }

   @Override
   public void unRegisterObserver(Observer observer) {
       int i = arrayObserve.indexOf(observer);
       if (i >= 0) {
           //將觀察者從列表中解除
           arrayObserve.remove(i);
       }

   }
   //通知因此觀察者數據更新了
   @Override
   public void notifyObservers() {

       for (int i = 0; i < arrayObserve.size(); i++) {
           Observer o = (Observer) arrayObserve.get(i);
           o.update(completeProgress, updateProgress);
       }
   }
}

3.構建一個觀察者接口Observer

public interface Observer {
    //更新數據
    void update(int completeProgress, int updateProgress);
 }

4.可構建一個展現數據的接口(可忽略)
有展現數據的方法,觀察者要實現這個方法 查看本例的 DisplaySchedule

public interface DisplaySchedule {
   void display();
}

5.定義觀察者(模擬該類就是產品經理觀察者),需實現接口Observes、DisplaySchedule(可忽略),
<1>、將主題Subject設置爲觀察者的屬性,並將其做爲觀察者的構造函數如 ProductManagerObserver.class
調用 developmentProgressSubject.registerObserver(this);將觀察者註冊到觀察列表中

public class ProductManagerObserver implements Observer, DisplaySchedule {

    private int completeProgress;//完成進度
    private int updateProgress;//更新進度
    //將主題當成觀察者的屬性
    private Subject developmentProgressSubject;

    public ProductManagerObserver(Subject developmentProgressSubject) {
        this.developmentProgressSubject = developmentProgressSubject;
        //註冊該觀察者
        developmentProgressSubject.registerObserver(this);
    }

    @Override
    public void display() {
        System.out.println("產品經理管理者顯示當前數據 完成進度爲: " + completeProgress + "更新修改進度爲:" + updateProgress);
    }

    @Override
    public void update(int completeProgress, int updateProgress) {
        this.completeProgress = completeProgress;
        this.updateProgress = updateProgress;
        display();
    }
}
測試

RunTest.class

public class RunTest {

    public static void main(String[] args) {

        DevelopmentProgressData developmentProgressData = new DevelopmentProgressData();
        ProductManagerObserver productManagerObserver = new ProductManagerObserver(developmentProgressData);
        ProjectManagerObserver projectManagerObserver = new ProjectManagerObserver(developmentProgressData);
        developmentProgressData.setCurrentData(34, 45);
        //當項目經理出差了,不觀察項目進度了就取消訂閱了
        developmentProgressData.unRegisterObserver(projectManagerObserver);
        //當前只有產品經理獲取到數據
        developmentProgressData.setCurrentData(46, 90);
    }
}
輸出結果
C:\Java\jdk1.8.0_161\bin\...
產品經理管理者顯示當前數據 完成進度爲: 34更新修改進度爲:45
項目管理真顯示當前數據完成進度爲: 34更新修改進度爲:45
產品經理管理者顯示當前數據 完成進度爲: 46更新修改進度爲:90

Process finished with exit code 0

根據java.util.observerable包下的Observerable.class實現觀察者模式功能

實現以下

具體實現步驟

1.首先觀察者須要實現java.util.Observer,而後將其被觀察者=>java.util.Observaerable做爲其觀察者的構造函數

<1>、經過observeable.addObserver(this)添加觀察者

public class BossMngObserver implements Observer, DisplayIllustrate {

 private Observable observable;
 private int valuableProductNum; //庫存有貴重產品
 private int normalProductNum;   //普通產品

 public BossMngObserver(Observable observable) {
     this.observable = observable;
     observable.addObserver(this);
 }

 @Override
 public void disPlay() {
     System.out.println("總經理觀察數據改變:貴重產品數量: " + valuableProductNum + "普通產品數量: " + normalProductNum);
 }
//<2>、實現 Observer更新數據方法
//看本例的包下的observe的三個類
 @Override
 public void update(Observable o, Object arg) {
     if (o instanceof InventoryData) {
         InventoryData inventoryData = (InventoryData) o;
         this.valuableProductNum = inventoryData.getValuableProductNum();
         this.normalProductNum = inventoryData.getNormalProductNum();
         disPlay();
     }
 }
  }

2.被觀察者須要繼承java.util.Observerable,

<1>、而後先調用setChanged()方法

<2>、在進行調用notifyObserves()更新數據

public class InventoryData extends Observable {

    private int valuableProductNum; //庫存有貴重產品
    private int normalProductNum;   //普通產品

    public void setCurrentData(int valuableProductNum, int normalProductNum) {
        this.valuableProductNum = valuableProductNum;
        this.normalProductNum = normalProductNum;
        statusChange();
    }

    private void statusChange() {
    //先調用 setChanged();
        setChanged();
        notifyObservers();
    }
 }
測試

3.Test.class

public class Test {
    public static void main(String[] args) {

        InventoryData inventoryData = new InventoryData();

        ValuableInfoMngObserver io = new ValuableInfoMngObserver(inventoryData);

        //io.deleteObserve();
        inventoryData.setCurrentData(20, 30);

        NormalInfoMngObserver no = new NormalInfoMngObserver(inventoryData);

        //no.deleteObserver();
        inventoryData.setCurrentData(15, 27);

        BossMngObserver bossMngObserver = new BossMngObserver(inventoryData);

        inventoryData.setCurrentData(10, 50);
    }
}

下載

觀察者模式案例代碼

總結

觀察者模式的讓咱們知道了在設計開發的時候必定要「多用組合,少用繼承」。

咱們設計開發是應該是針對接口變成,而不針對實現編程。

在java.util.*下的Observer和Observable能夠實現觀察者,可是Observable是一個類,這樣咱們是不違背了「多用組合少用繼承」的OO編程思想,是的沒錯在java.util.Observable類違背了該規則。

個人GitHub博客

設計模式

你們能夠進入這裏學習設計模式

相關文章
相關標籤/搜索