我的武林祕籍設計模式之觀察者模式
自從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);
}
}
執行結果:
有了這個設計,夏流童鞋不僅受到了大伯大媽的好評,也幫助他成為杭州傑出青年的好榜樣。
觀察者模式的官方定義是:定義物件見的一種一對多的依賴關係,當一個物件的狀態傳送變化時,所有依賴它的物件都得到通知並被自動更新。