1. 程式人生 > >我的武林祕籍設計模式之觀察者模式

我的武林祕籍設計模式之觀察者模式

自從jack的鴨子游戲得到成功之後,jack的好朋友夏流就覺得心裡癢癢的,也想做出一番作為來。

所以,今天的主人公就是這位夏流童鞋。夏流是錢塘江觀測站的一名觀測員,需要向人民群眾反饋錢塘江的水位,水溫,風力,及水裡的魚量等資訊。在這裡經常會有許多市民從他這裡打聽當日的錢塘江的這些資訊,以便於他們瞭解,好決定是不是要去江邊做點什麼。

於是夏流決定做一個系統,能夠自動反饋錢塘江的資訊給熱心市民。每當錢塘江的相關資訊有變化時,會自動傳送到熱心市民手機上,通知他們。

在觀察者模式中,夏流做的這個錢塘江觀測系統便是一個主題(Subject),熱心市民便是一個觀察者(Observer)

我們定義兩個介面Subject和Observer ,因為我們是有格局,有情懷的程式猿,所以一般我們都是要面向介面程式設計。

在Subject中,我們定義三個方法,新增觀察者,刪除觀察者,通知觀察者。

在Observer中,只要更新主題發過來的訊息就好,所以只有一個更新方法。

然後我們實現具體主題,也就是錢塘江觀測站,在錢塘江觀測站中,水位,水溫,風力,魚的條數都是它的屬性,還有一個是觀察者列表,所有的觀察者都存在這個ObserverList裡。當有新的資訊更新時,他就呼叫notifyObserver方法通知他們的觀察者去更新資訊。

接著呢是實現觀察者了,這個市民就是具體的觀察者了。觀察者中維護了一個主題,這個主題就是他關注的那個主題,也就是錢塘江觀測站了,它有了這個主題就能夠把自己給新增到這個主題的觀察者列表中了。

 

夏流按照這個思路設計完了該系統,卻遭到了一些熱心市民的抱怨。一位愛釣魚的王大伯說,我只要當天的水位和魚的數量資訊,其他資訊這麼多給我並沒有軟用。

另一位愛游泳的劉叔叔說,我只要水溫很風力資訊就夠了,這樣我才能知道我該不該下水游泳(當然在錢塘江游泳釣魚啥的都是非常危險的,這裡只是舉個例子)

另一位愛拍照的王阿姨說,我只要風力資訊,希望我能借助風力吹起我美麗的秀髮,用我的美顏相機定格住那美麗的瞬間

夏流聽到了各位熱心市民的意見,決定改善一下系統。

他想這樣的話,就在通知觀察者的時候,讓update方法不帶引數。反正他們內部已經維護了一個主題,讓他們自己根據自己所需去從這個主題中拿資料就好了。

以下是修改後的類圖

主要還是修改觀察者中的update方法,一個是直接通過update方法一股腦把所有資訊傳過來,另一個是通過觀察者自身所維護的主題中去取。

接著有了這個設計,我們好實現程式碼了

package qiantang;

/**
 * Created by huangx on 2018/11/14.
 */
public interface Observer {
    void update();

    void display();
}
package qiantang;

/**
 * Created by huangx on 2018/11/14.
 */
public interface Subject {
     void addObserver(Observer observer);
     void deleteObserver(Observer observer);
     void notifyObserver();
}
package qiantang;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by huangx on 2018/11/14.
 */
public class QiangtangRiverStation implements Subject {

    private int height;
    private int tempature;
    private int wind;
    private int fish;
    private List<Observer> observerList = new ArrayList<Observer>();

    public void addObserver(Observer observer) {
        observerList.add(observer);
    }

    public void deleteObserver(Observer observer) {
        observerList.remove(observer);
    }

    public void notifyObserver() {
        for (Observer observer : observerList) {
            observer.update();
        }
    }

    public void setNewInfo(int height, int tempature, int wind, int fish) {
        this.height = height;
        this.tempature = tempature;
        this.wind = wind;
        this.fish = fish;
        notifyObserver();
    }

    public int getHeight() {
        return height;
    }

    public int getTempature() {
        return tempature;
    }

    public int getWind() {
        return wind;
    }

    public int getFish() {
        return fish;
    }

}
package qiantang;

/**
 * Created by huangx on 2018/11/14.
 */
public class FishCitizen implements Observer {
    private String name;
    private int fish;
    private int height;
    private Subject subject;

    public FishCitizen(String name, Subject subject) {
        this.name = name;
        this.subject = subject;
        subject.addObserver(this);//關鍵一步把自己扔到主題中去
    }

    public void update() {
        if (subject instanceof QiangtangRiverStation) {
            this.fish = ((QiangtangRiverStation) subject).getFish();
            this.height = ((QiangtangRiverStation) subject).getHeight();
        }
        display();
    }

    public void display() {
        System.out.println("我是" + name + ",今天的魚量是" + fish + ",今天 的水位是" + height);
    }
}
package qiantang;

/**
 * Created by huangx on 2018/11/14.
 */
public class PhotoCitizen implements Observer {
    private String name;
    private int wind;
    private Subject subject;

    public PhotoCitizen(String name, Subject subject) {
        this.name = name;
        this.subject = subject;
        subject.addObserver(this);
    }

    public void update() {
        if (subject instanceof QiangtangRiverStation) {
            this.wind = ((QiangtangRiverStation) subject).getWind();
        }
        display();
    }

    public void display() {
        System.out.println("我是" + name + ",今天的風力是" + wind + "今天的我一定是個小公舉");
    }
}
package qiantang;

/**
 * Created by huangx on 2018/11/14.
 */
public class SwimCitizen implements Observer {
    private String name;
    private int tempature;
    private int wind;
    private Subject subject;

    public SwimCitizen(String name, Subject subject) {
        this.name = name;
        this.subject = subject;
        subject.addObserver(this);
    }

    public void update() {
        if (subject instanceof QiangtangRiverStation) {
            this.tempature = ((QiangtangRiverStation) subject).getTempature();
            this.wind = ((QiangtangRiverStation) subject).getWind();
        }
        display();
    }

    public void display() {
        System.out.println("我是" + name + ",今天的水溫是" + tempature + ",今天 的風力是" + wind);
    }
}
package qiantang;

/**
 * Created by huangx on 2018/11/14.
 */
public class TestApplication {
    public static void main(String[] args) {
        QiangtangRiverStation qiangtangRiverStation=new QiangtangRiverStation();
        SwimCitizen swimCitizen=new SwimCitizen("劉叔叔",qiangtangRiverStation);
        FishCitizen fishCitizen=new FishCitizen("王大伯",qiangtangRiverStation);
        PhotoCitizen photoCitizen=new PhotoCitizen("王阿姨",qiangtangRiverStation);
        qiangtangRiverStation.setNewInfo(11,22,33,44);
        qiangtangRiverStation.setNewInfo(55,66,77,88);
    }
}

執行結果:

 

有了這個設計,夏流童鞋不僅受到了大伯大媽的好評,也幫助他成為杭州傑出青年的好榜樣。

觀察者模式的官方定義是:定義物件見的一種一對多的依賴關係,當一個物件的狀態傳送變化時,所有依賴它的物件都得到通知並被自動更新。