Observer模式(觀察者設計模式)


Observer 設計模式?

在Observer模式中,當觀察對象的狀態發生變化時,會通知給觀察者。Observer模式適用於根據對象狀態進行相應處理的場景。

  • Observer 並非主動觀察,而是被動觀察,實際可以又稱之為發布-訂閱者模式

  • MVC
    Model、View、Controller,並且Model里面的操作不依賴於具體形式的內部模型,通常情況下:
    一個Model對應多個View,這里也是使用Observer設計模式最多的地方

  • java中觀察者接口

在package java.util;下存在了Observer接口,按照二類定義模式,允許傳遞對象,以及附帶參數

void update(Observable o, Object arg);

  • 使用注意:java.util.observer接口和java.util.observable類並不好用。理由很簡單,傳遞給java.util.observer接口的Subject角色必須是java.util.observable類型(或者它的子類型)的。但Java只能單一繼承,也就說如果Subject角色已經是某個類的子類了,那么它將無法繼承java.util.observable類。(單個使用還是可以的)

理清職責

  • 實現功能:根據不同的觀察者顯示字符串的方式也不一樣!

|名字=======》》》說明
|Observer || 表示觀察者的接口
|NumberGenerator || 表示生成數值的對象的抽象類
|RandomNumberGenerator || 生成隨機數的類
|Digitobserver || 表示以數字形式顯示數值的類
|Graphobserver || 表示以簡單的圖示形式顯示數值的類
|Main || 測試程序行為的類

  • Observer調用順序問題:
    當在Observer存在多個需要通知的方法時,方法一多,容易出現混亂,所以你這里使用template設計模式將在Observer定義的使用順序,提前安排好,
    那么子類去實現就行了。出現更改調用順序的時機,只需要去Observer中查看。

  • 可替換性原則:

  1. 利用抽象類與接口從具體的類中抽象出方法
    2.將實例作為參數傳遞到類中,或者在類的字段中保存實例時,不要使用具體的類型,而是使用抽象類型接口作為參數傳遞。
  • 相關設計模式

◆Mediator模式
在Mediator模式中,有時會使用Observer 模式來實現Mediator角色與Colleague角色之間的通信。
就“發送狀態變化通知”這一點而言,Mediator模式與Observer模式是類似的。不過,兩種模式中,通知的目的和視角不同。
在Mediator模式中,雖然也會發送通知,不過那不過是為了對Colleague角色進行仲裁而已。
而在Observer模式中,將Subject角色的狀態變化通知給Observer角色的目的則主要是為了使Subject角色和Observer角色同步。

UML

類圖:

Code

  • Observer 、NumberGenerator
public interface Observer {

    /**
     * 通知concreateObserver
     * @param numberGenerator
     */
    void update(NumberGenerator numberGenerator);
}

public abstract class NumberGenerator {

    private List<Observer> observers=new ArrayList<>();

    /**
     * 增加觀察者
     * @param observer
     */
    public void addObserver(Observer observer){observers.add(observer);};

    /**
     * 移除觀察者
     * @param observer
     */
    public void deleteObserver(Observer observer){observers.remove(observer);};

    /**
     * 通知所有的觀察者
     */
    protected void notifyObservers(){
        Iterator<Observer> it = observers.iterator();
        while (it.hasNext()){
            Observer next = it.next();
            next.update(this);
        }
    }

    /**
     * 獲取數值
     */
    public abstract int getNumber();

    /**
     * 生成數值
     */
    public abstract void excute();

}


  • Graphobserver 、Digitobserver 兩個觀察者
public class Digitobserver implements Observer {

    @Override
    public void update(NumberGenerator numberGenerator) {
        System.out.println(this.getClass().getName()+":"+numberGenerator.getNumber());

        try {
            Thread.sleep(100);
        }catch (InterruptedException e){
            e.printStackTrace();
        }

    }
}

public class Graphobserver implements Observer {
    @Override
    public void update(NumberGenerator numberGenerator) {
        System.out.println(this.getClass().getName()+":");
        for (int i = 0; i < numberGenerator.getNumber(); i++) {
            System.out.print("*");
        }
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}



  • RandomNumberGenerator

public class RandomNumberGenerator extends NumberGenerator{

    private Random random=new Random();

    private int number;

    @Override
    public int getNumber() {
        return number;
    }

    /**
     * 生成一次數值,通知一次觀察者
     */
    @Override
    public void excute() {
        for (int i = 0; i < 20; i++) {
            number=random.nextInt(50);
            notifyObservers();
        }
    }
}


  • MainT
public class MainT {

    public static void main(String[] args) {
        NumberGenerator generator = new RandomNumberGenerator();

        // 觀察者
        Digitobserver digitobserver = new Digitobserver();

        Graphobserver graphobserver = new Graphobserver();

        generator.addObserver(digitobserver);
        generator.addObserver(graphobserver);

        generator.excute();
    }
}




免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM