1. 程式人生 > >Observer模式(觀察者設計模式)

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();
    }
}