詳解Java編程的Observer觀察者設(shè)計(jì)模式
java語(yǔ)言里包含了許多對(duì)設(shè)計(jì)模式的直接支持,如command模式,agent模式,observer模式等。雖然java提供的對(duì)這些模式的支持很簡(jiǎn)單,不能滿足比較復(fù)雜的應(yīng)用。但在簡(jiǎn)單的場(chǎng)景下,使用這些類往往能夠得到立桿見(jiàn)影的效果。所以,如果沒(méi)有什么特殊需求,還是最好利用java的這些類。
Observer模式,又稱監(jiān)聽(tīng)模式,觀察者模式,是經(jīng)典設(shè)計(jì)模式之一(one of GOF)。java語(yǔ)言中,對(duì)這種模式支持的類和接口主要有以下幾個(gè),全部來(lái)自java.beans包:
java.beans.PropertyChangeListener (interface) java.beans.PropertyChangeSupport (class) java.beans.PropertyChangeEvent (class) java.beans.PropertyChangeListener
這是一個(gè)接口,很顯然,所有實(shí)現(xiàn)這個(gè)接口的類就是listener啦(或者叫observer),它會(huì)對(duì)被監(jiān)聽(tīng)的對(duì)象的某些變化感興趣。這個(gè)接口就一個(gè)方法:
public void propertyChange(PropertyChangeEvent evt) {
// TODO Auto-generated method stub
}
接口定義很簡(jiǎn)單,作用也很明顯。接受一個(gè)event(被監(jiān)聽(tīng)者產(chǎn)生的PropertyChangeEvent),然后根據(jù)這個(gè)event做點(diǎn)反應(yīng)。
java.beans.PropertyChangeSupport
這個(gè)類用在被觀察者的類里,用來(lái)保存注冊(cè)的觀察者,并負(fù)責(zé)向他們提供被觀察者的變化信息。這個(gè)類的方法也不多,不過(guò)還是只介紹100%用到的,要不腦子就不夠使了,呵呵。
public PropertyChangeSupport(Object sourceBean)
這是構(gòu)造函數(shù),參數(shù)就是被監(jiān)聽(tīng)者。PropertyChangeListener一般作為被監(jiān)聽(tīng)者的一個(gè)屬性。一般如下使用:
private PropertyChangeSupport listeners = new PropertyChangeSupport(this);
注意,這個(gè)listeners可不是只代表一個(gè)監(jiān)聽(tīng)者,他可能是一群監(jiān)聽(tīng)者。那么如何這些listeners是誰(shuí)呢?這回用到下面的方法了。
public void addPropertyChangeListener(PropertyChangeListener listener)
這個(gè)類太容易了,把監(jiān)聽(tīng)者加進(jìn)來(lái)。就像開(kāi)十七大一樣,記者想要采訪,就得先登記一下。顯然這個(gè)方法可以多次調(diào)用(add嘛)。有加就有減:
public void removePropertyChangeListener(PropertyChangeListener listener)
如果這個(gè)監(jiān)聽(tīng)者對(duì)被監(jiān)聽(tīng)者的任何變化多不感興趣了,就被被監(jiān)聽(tīng)者趕了出去。
好了,記者都到齊了,被監(jiān)聽(tīng)者有變化了就該通知人家了,使用如下方法的一個(gè):
public void firePropertyChange(PropertyChangeEvent evt)
public void firePropertyChange(String propertyName,
boolean oldValue,
boolean newValue)
public void firePropertyChange(String propertyName,
int oldValue,
int newValue)
public void firePropertyChange(String propertyName,
Object oldValue,
Object newValue)
實(shí)際上,后三個(gè)方法的參數(shù)都會(huì)封裝成PropertyChangeEvent,然后調(diào)用第一個(gè)方法。不過(guò)在實(shí)際中,我們還是喜歡直接調(diào)用后三個(gè)中的一個(gè),封裝的事我們就不管了。后三個(gè)方法的參數(shù)都是三個(gè),其中的oldValue和newValue就是改變前后的值,第一個(gè)就是給改變一個(gè)名字,好讓監(jiān)聽(tīng)者們根據(jù)這個(gè)名子來(lái)做響應(yīng)。就像開(kāi)會(huì),政府的所有信息都會(huì)被記者聽(tīng)到,但是有的記者只對(duì)臺(tái)灣問(wèn)題感興趣,而有的記者對(duì)中日問(wèn)題感興趣。
對(duì)PropertyChangeSupport方法的介紹就這么多吧。注意,PropertyChangeSupport既然被用到了被觀察者的類(一般是一個(gè)model)里,那么他的這些方法就只在被觀察這里調(diào)用。
java.beans.PropertyChangeEvent
這個(gè)類我也懶得介紹,看看他的主要方法就明白怎么回事了
public String getPropertyName() public Object getNewValue() public Object getOldValue()
就者三個(gè)類,再有就是具體問(wèn)題具體分析了。來(lái)個(gè)例子吧,首先是被觀察者:
public class Domain{
protected String id;
protected String name;
protected String desName;
protected PropertyChangeSupport listeners = new PropertyChangeSupport(this);
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
firePropertyChange("Domain.id", null, id);
}
public String getDesName() {
return desName;
}
public void setDesName(String desName) {
this.desName = desName;
firePropertyChange("Domain.desName", null, desName);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
firePropertyChange("Domain.name", null, name);
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
listeners.addPropertyChangeListener(listener);
}
public void firePropertyChange(String propName, Object oldValue, Object newValue) {
listeners.firePropertyChange(propName, oldValue, newValue);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
listeners.removePropertyChangeListener(listener);
}
}
有人對(duì)Domain的三個(gè)屬性感興趣。下面就是這些人中的一個(gè):
public class SimpleObserver implements PropertyChangeListener {
....
@Override
public void propertyChange(PropertyChangeEvent evt) {
if(evt.getPropertyName().equals("Domain.name")){
//do some work
}
}
}
下面是個(gè)簡(jiǎn)單的測(cè)試類:
public class SimpleTest{
public static void main(String[] args) {
SimpleObserver observer = new SimpleObserver();
Domain domain = new Domain();
domain.addPropertyChangeListener(observer);
domain.setName("yangsq");
......
}
}
很顯然,可以觀察到SimpleObserver中propertyChange方法的執(zhí)行。
相關(guān)文章
Java Swing實(shí)現(xiàn)簡(jiǎn)單的體重指數(shù)(BMI)計(jì)算器功能示例
這篇文章主要介紹了Java Swing實(shí)現(xiàn)簡(jiǎn)單的體重指數(shù)(BMI)計(jì)算器功能,涉及Java Swing窗口組件布局、響應(yīng)及數(shù)值運(yùn)算相關(guān)操作技巧,需要的朋友可以參考下2017-12-12
Java生成獨(dú)一無(wú)二的工單號(hào)實(shí)例
這篇文章主要介紹了Java生成獨(dú)一無(wú)二的工單號(hào)實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-09-09
Spring用三級(jí)緩存處理循環(huán)依賴的方法詳解
這篇文章主要介紹了Spring用三級(jí)緩存處理循環(huán)依賴的方法,在Spring?框架中,依賴注入是其核心特性之一,它允許對(duì)象之間的依賴關(guān)系在運(yùn)行時(shí)動(dòng)態(tài)注入,然而,當(dāng)多個(gè)Bean之間的依賴關(guān)系形成一個(gè)閉環(huán)時(shí),就會(huì)出現(xiàn)循環(huán)依賴問(wèn)題,本文就為解決此問(wèn)題,需要的朋友可以參考下2025-02-02
Java實(shí)現(xiàn)大文件的切割與合并操作示例
這篇文章主要介紹了Java實(shí)現(xiàn)大文件的切割與合并操作,結(jié)合實(shí)例形式分析了java基于io及util操作大文件按指定個(gè)數(shù)分割與合并相關(guān)操作技巧,需要的朋友可以參考下2018-07-07
Eclipse將Maven項(xiàng)目打成jar包的方法
這篇文章主要介紹了Eclipse將Maven項(xiàng)目打成jar包的方法,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2007-09-09
Java實(shí)現(xiàn)簡(jiǎn)單的迷宮游戲詳解
迷宮游戲作為經(jīng)典的小游戲,一直深受大家的喜愛(ài)。本文小編將為大家詳細(xì)介紹一下如何用Java實(shí)現(xiàn)一個(gè)簡(jiǎn)單的迷宮小游戲,感興趣的可以動(dòng)手試一試2022-02-02
java實(shí)現(xiàn)時(shí)間與字符串之間轉(zhuǎn)換
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)時(shí)間與字符串之間轉(zhuǎn)換,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-12-12
mybatis.type-aliases-package的作用及用法說(shuō)明
這篇文章主要介紹了mybatis.type-aliases-package的作用及用法說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-01-01
sin(x)如何求解的java代碼實(shí)現(xiàn)方法
這篇文章主要為大家介紹了sin(x)如何求解的java代碼實(shí)現(xiàn)方法示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-04-04

