學(xué)校里有個十分可愛的女孩子性锭,很多男孩都紛紛加入了她的粉絲行列赠潦,大家爭先恐后的去搜集她的信息。這個時候女孩的室友草冈,同學(xué)都開始向她抱怨她奥,她也深感愧疚,感覺麻煩了周圍的朋友怎棱。于是哩俭,她決定公開自己的狀態(tài),前提是不再去麻煩她身邊的人拳恋。開始凡资,她公開自己每天吃飯和學(xué)習(xí)的狀態(tài),只要她的粉絲在她這里進行注冊诅岩,就可以不費吹灰之力的收到自己的動態(tài)信息讳苦,這對于粉絲而言簡直是個天大的好消息...這個時候一個程序員路過,看到了這個現(xiàn)象吩谦,靈光一閃鸳谜,這是觀察者模式。首先式廷,將女孩抽象成一個類咐扭,她的行為我們也可以寫成方法,于是有了下面這兩個類。
public interface Girl {
public void addFans(Fans fans);
public void removeFnas(Fans fans);
public void notifyFans();
}
public class LovelyGirl implements Girl {
private String eatState = "Inexact";
private String studyState = "Inexact";
private ArrayList<Fans> fanses;
public LovelyGirl() {
fanses = new ArrayList<>();
}
@Override
public void addFans(Fans fans) {
fanses.add(fans);
}
@Override
public void removeFnas(Fans fans) {
int i = fanses.indexOf(fans);
if (i >= 0) {
fanses.remove(i);
}
}
@Override
public void notifyFans() {
for (int i = 0; i < fanses.size(); i++) {
Fans fans = fanses.get(i);
fans.update(eatState, studyState);
}
}
public void setEatState(String eatState) {
this.eatState = eatState;
notifyFans();
}
public void setStudyState(String studyState) {
this.studyState = studyState;
notifyFans();
}
}
這里蝗肪,將女孩寫成了一個接口袜爪。畢竟,人總會見異思遷的嘛薛闪,萬一學(xué)校里來了個很漂亮的女孩子呢辛馆?那恐怕就要多出一個 BeautyGirl
類了。講完了女孩豁延,我們也得講講那些粉絲吧昙篙,粉絲有很多,他們的目的也只有一個 ——獲取自己心儀女孩的最新信息诱咏。那好吧苔可,為了讓你們和女神保持一致,也為你們寫一個接口吧袋狞。
public interface Fans {
public void update(String eatState, String studyState);
}
有了接口之后焚辅,眾多的粉絲們就可以實現(xiàn)這個接口,去獲得最新信息了苟鸯。比如說粉絲甲和粉絲乙——
public class FansOne implements Fans {
@Override
public void update(String eatState, String studyState) {
System.out.println("I am fans one : " + eatState + ", " + studyState);
}
}
public class FansTwo implements Fans {
@Override
public void update(String eatState, String studyState) {
System.out.println("I am fans two : " + eatState + ", " + studyState);
}
}
好了同蜻,所有準(zhǔn)備工作已經(jīng)完成了,不過這個時候已經(jīng)中午了倔毙,女孩說了埃仪,我要開始吃飯了,比如像下面這樣
public class Client {
public static void main(String[] args) {
LovelyGirl girl = new LovelyGirl();
FansOne fansOne = new FansOne();
girl.addFans(fansOne);
FansTwo fansTwo = new FansTwo();
girl.addFans(fansTwo);
girl.setEatState("I am eating");
}
}
打印結(jié)果如下
I am fans one : I am eating, Inexact
I am fans two : I am eating, Inexact
其實陕赃,上面這么一個例子就是我們常說的觀察者模式卵蛉。觀察者模式定義了對象之間的一對多依賴,當(dāng)一個對象狀態(tài)改變時么库,它的所有依賴者都會收到通知并且自動更新傻丝。生活中很多地方用到這種模式,比如說天氣預(yù)報訂閱系統(tǒng)诉儒,報紙訂閱系統(tǒng)等葡缰。
上面這個例子還有可以修改之處,因為我們只寫了推送功能忱反,如果粉絲們想主動獲取信息呢泛释?如果有的粉絲對你的學(xué)習(xí)狀態(tài)不感興趣并且表示再也不想收到關(guān)于學(xué)習(xí)的信息推送了。那么該怎么進行改進呢温算?正好借這個機會怜校,我們來看看 Java
為我們內(nèi)置的觀察者模式。Java
為我們提供了 Observer
接口和 Observable
類注竿,下面我們來介紹一下如何使用茄茁。
如何把對象變成觀察者 魂贬?
實現(xiàn)觀察者接口,然后調(diào)用Observable
對象的addObserver()
方法裙顽。不在想當(dāng)觀察者對象的時候付燥,調(diào)用deleteObserver()
方法就可以了。-
可觀察者如何送出通知 愈犹?
首先键科,需要繼承java.util.Observable
類產(chǎn)生可觀察者類,然后需要兩個步驟漩怎。- 先調(diào)用
setChanged()
方法萝嘁,標(biāo)記狀態(tài)已經(jīng)改變的事實。 - 然后調(diào)用兩種
notifyObservers()
方法中的一個 :notifyObservers()
或者notifyObservers(Object arg)
- 先調(diào)用
觀察者如何接受通知扬卷?
觀察者實現(xiàn)了更新的方法,但是方法的簽名不太一樣 :update(Observable o, Object arg)
酸钦。 這個時候就可以實現(xiàn)兩種不同的效果怪得。如果我們將Object
屬性不指定,也就是只傳遞Observable
對象的值卑硫,這個時候就是默認(rèn)不推送給觀察者任何信息徒恋,不過觀察者可以通過被觀察者提供的get
方法主動獲取消息(這里也暗示了一個信息,就是我們的觀察者內(nèi)部需要獲得被觀察者的引用)欢伏。如果這里我們指定了Object
的對象入挣,那么被觀察者會將信息推送給觀察者。
注意哦硝拧,以上我們提到的 update()
方法中的 Object
參數(shù)和被觀察者中notifyObservers(Object o)
中的 Object
是對應(yīng)的径筏。
利用以上介紹的信息,去改寫以上的代碼障陶。
public class LovelyGirl extends Observable {
private String eatState = "Inexact";
private String studyState = "Inexact";
public void setEatState(String eatState) {
this.eatState = eatState;
}
public void setStudyState(String studyState) {
this.studyState = studyState;
}
public String getEatState() {
return eatState;
}
public String getStudyState() {
return studyState;
}
public void stateChanged() {
setChanged();
notifyObservers();
}
}
可見滋恬,在這里我們使用了無參數(shù)的 notifyObservers()
方法,這也就意味著抱究,我們采用了不主動推送的方式恢氯。還有這里的 setChanged()
,是 Observable
類中實現(xiàn)的一個方法鼓寺,這個方法的作用是標(biāo)記狀態(tài)已經(jīng)改變的事實勋拟,只有調(diào)用了這個函數(shù),被觀察者才會將最新的狀態(tài)通知觀察者妈候。
public class FansOne implements Observer {
private Observable observable;
public FansOne(Observable observable) {
this.observable = observable;
observable.addObserver(this);
}
@Override
public void update(Observable o, Object arg) {
if (o instanceof LovelyGirl) {
LovelyGirl girl = (LovelyGirl) o;
System.out.println("eatState : " + girl.getEatState() +
" studyState : " + girl.getStudyState());
}
}
}
可見敢靡,這里我們就將 addObserver()
方法寫到了這里,因為我們既然在觀察者中引用了被觀察者對象州丹,也就沒有必要將添加的方法放入主函數(shù)了醋安。這個時候再看看主函數(shù)的代碼以及輸出結(jié)果
public class Client {
public static void main(String[] args) {
LovelyGirl girl = new LovelyGirl();
FansOne fansOne = new FansOne(girl);
girl.setEatState("I am eating...");
}
}
eatState : I am eating... studyState : Inexact
可見杂彭,利用了Java
內(nèi)置的觀察者模式之后,我們自己動手寫的代碼量就就減少了許多吓揪,而且邏輯也更加清晰了亲怠。不過我感覺 Java
內(nèi)部將 Observable
設(shè)置為一個類還是有缺點的,因為Java
并不允許多重繼承柠辞,這就限制了 Observable
的復(fù)用能力~