JavaBean PropertyChange 之設計模式Observer(轉)
java語言里包含了許多對設計模式的直接支持,如command模式,agent模式,observer模式等。雖然java提供的對這些模式的支持很簡單,不能滿足比較復雜的應用。但在簡單的場景下,使用這些類往往能夠得到立桿見影的效果。所以,如果沒有什么特殊需求,還是最好利用java的這些類。
java.beans.PropertyChangeListener (interface)
java.beans.PropertyChangeSupport
java.beans.PropertyChangeEvent
- java.beans.PropertyChangeListener
- public
voidpropertyChange(PropertyChangeEvent evt) { - //
TODO Auto-generated method stub - }
接口定義很簡單,作用也很明顯。接受一個event(被監聽者產生的PropertyChangeEvent),然后根據這個event做點反應。
-
java.beans.PropertyChangeSupport
- public
PropertyChangeSupport(Object sourceBean)
- private
newPropertyChangeSupport listeners = this);PropertyChangeSupport(
- public
voidaddPropertyChangeListene r(PropertyChangeListener listener)
- public
voidremovePropertyChangeList ener(PropertyChangeListener listener)
如果這個監聽者對被監聽者的任何變化多不感興趣了,就被被監聽者趕了出去。
好了,記者都到齊了,被監聽者有變化了就該通知人家了,使用如下方法的一個:
- public
voidfirePropertyChange(PropertyChangeEvent evt) -
- public
voidfirePropertyChange(String propertyName, -
booleanoldValue, -
booleannewValue) -
- public
voidfirePropertyChange(String propertyName, -
intoldValue, -
intnewValue) -
- public
voidfirePropertyChange(String propertyName, -
Object oldValue, -
Object newValue)
實際上,后三個方法的參數都會封裝成PropertyChangeEvent,然后調用第一個方法。不過在實際中,我們還是喜歡直接調用后三個中的一個,封裝的事我們就不管了。后三個方法的參數都是三個,其中的oldValue和 newValue就是改變前后的值,第一個就是給改變一個名字,好讓監聽者們根據這個名子來做響應。就像開會,政府的所有信息都會被記者聽到,但是有的記者只對臺灣問題感興趣,而有的記者對中日問題感興趣。
對PropertyChangeSupport方法的介紹就這么多吧。注意,PropertyChangeSupport既然被用到了被觀察者的類(一般是一個model)里,那么他的這些方法就只在被觀察這里調用。
- java.beans.PropertyChangeEvent
- public
String getPropertyName() - public
Object getNewValue() - public
Object getOldValue()
就者三個類,再有就是具體問題具體分析了。來個例子吧,首先是被觀察者:
- public
classDomain{ -
protectedString id; -
protectedString name; -
protectedString desName; -
-
protected newPropertyChangeSupport listeners = this);PropertyChangeSupport( -
-
publicString getId() { -
returnid; -
} -
-
public voidsetId(String id) { -
this.id= id; -
"Domain.id",firePropertyChange( null,id); -
} -
-
publicString getDesName() { -
returndesName; -
} -
-
public voidsetDesName(String desName) { -
this.desName= desName; -
"Domain.desName",firePropertyChange( null,desName); -
} -
-
publicString getName() { -
returnname; -
} -
-
public voidsetName(String name) { -
this.name= name; -
"Domain.name",firePropertyChange( null,name); -
} -
-
public voidaddPropertyChangeListene r(PropertyChangeListener listener) { -
listeners.addPropertyChangeListene r(listener); -
} -
-
public voidfirePropertyChange(String propName, Object oldValue, Object newValue) { -
listeners.firePropertyChange(propName, oldValue, newValue); -
} -
-
public voidremovePropertyChangeList ener(PropertyChangeListener listener) { -
listeners.removePropertyChangeList ener(listener); -
} - }
有人對Domain的三個屬性感興趣。下面就是這些人中的一個:
- public
class implementsSimpleObserver PropertyChangeListener { -
-
.... -
-
@Override -
public voidpropertyChange(PropertyChangeEvent evt) { -
if(evt.getPropertyName().equals("Domain.name")){ -
//dosome work -
} -
} -
- }
下面是個簡單的測試類:
- public
classSimpleTest{ -
public static voidmain(String[] args) { -
newSimpleObserver observer = SimpleObserver(); -
newDomain domain = Domain(); -
domain.addPropertyChangeListene r(observer); -
"yangsq");domain.setName( -
...... -
} - }
JavaBean的屬性與一般Java程序中所指的屬性,或者說與所有面向對象的程序設計語言中對象的屬性是一個概念,在程序中的具體體現就是類中的變量。在JavaBean的設計中,按照屬性的不同作用又細分為四類:單值屬性;索引屬性;關聯屬性;限制屬性。
本文主要介紹如何使用PropertyChangeSupport類來支持關聯屬性事件的觸發。
1.關聯屬性
關聯屬性,也稱之為綁定屬性。綁定屬性會在屬性值發生變化時,通知所有相關的監聽器。為了實現一個綁定屬性,必須實現兩個機制。
1) 無論何時,只要屬性的值發生變化,該bean必須發送一個PropertyChange事件給所有已注冊的監聽器。該變化可能發生在調用set方法時,或者程序的用戶做出某種動作時。
2) 為了使感興趣的監聽器能夠進行注冊,bean必須實現以下兩個方法:
void addPropertyChangeListene
void removePropertyChangeList
2.使用PropertyChangeSupport
可以通過java.bean包下的PropertyChangeSupport類來管理監聽器。要使用這個類,bean必須有一個此類的數據域。
private PropertyChangeSupport changes = new PropertyChangeSupport(this);
這樣就可以將添加和移除監聽器的任務交給這個對象。
public void addPropertyChangeListene
changes.addPropertyChangeListene
}
public void removePropertyChangeList
changes.removePropertyChangeList
}
當bean的屬性發生變化時,使用PropertyChangeSupport對象的firePropertyChange方法,它會將一個事件發送給所有已經注冊的監聽器。該方法有三個參數:屬性的名字、舊的值以及新的值。屬性的值必須是對象,如果是簡單數據類型,則必須進行包裝。
changes.firePropertyChange("ourString", oldString, newString);
所有注冊的監聽器實現PropertyChangeListener接口,該接口中只有一個方法。
public void propertyChange(PropertyChangeEvent e);
當bean的屬性值發生變化時,該方法中的代碼就會被觸發。可以通過
e.getOldValue();
e.getNewValue();
來得到changes.firePropertyChange("ourString", oldString, newString);中的oldString和newString。
3.為什么要使用PropertyChangeSupport
使用這個類
還有一個好處是,這個類支持fire帶索引的屬性改變事件(詳見java.bean.IndexedPropertyChangeEve
void fireIndexedPropertyChang
4.示例
MyBoundBean類(具體代碼見附件)是一個JavaBean,我們關注它的唯一一個屬性ourString的變化情況,它的初始值是Hello。并通過PropertyChange類來管理監聽器。注意在set方法中會調用firePropertyChange方法。
MyBoundBean.java
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
public class MyBoundBean {
String ourString = "Hello";
private PropertyChangeSupport changes = new PropertyChangeSupport(this);
public void setString(String newString) {
String oldString = ourString;
ourString = newString;
changes.firePropertyChange("ourString", oldString, newString);
}
public String getString() {
return ourString;
}
public void addPropertyChangeListene
changes.addPropertyChangeListene
}
public void removePropertyChangeList
changes.removePropertyChangeList
}
}
MyBoundBean b = new MyBoundBean();
…
public void actionPerformed(ActionEvent e) {
jButton1.setText(textBox.getText());
b.setString(textBox.getText());
}
目標bean的屬性一改變(注意,初始值是"Hello"),將會觸發propertyChange方法的執行。將文本框的內容設置為目標bean的ourString屬性的舊值,同時,將jButton2的test設置成目標bean的ourString屬性的新值。
public void propertyChange(PropertyChangeEvent e) {
if (e.getSource() == b) {
textBox.setText(e.getOldValue().toString());
jButton2.setText(e.getNewValue().toString());
}
}
如果不實現PropertyChangeListener接口的話,可以使用匿名內部類來達到同樣的效果。(具體代碼見附件MyCallBound2.java)
MyBoundBean b = new MyBoundBean();
…
b.addPropertyChangeListene
public void propertyChange(PropertyChangeEvent e) {
// 這樣一來,我們就可以用自己定義的名字實現事件
ourString_propertyChange(e);
}
});
這樣一來,我們就可以用自己定義的名字實現事件。
void ourString_propertyChange(PropertyChangeEvent e) {
if (e.getSource() == b) {
textBox.setText(e.getOldValue().toString());
jButton2.setText(e.getNewValue().toString());
}
}
很顯然,可以觀察到SimpleObserver中propertyChange方法的執行。
posted on 2011-02-13 18:26 九寶 閱讀(942) 評論(0) 編輯 收藏 所屬分類: Java Study(JavaThinking4)