觀察者模式體驗就是一個:
問題:在做UI設計時,遇到一個問題,就是當我點擊一個自定義對話框的復選框時,自定義對話框的父界面必須做出相應的改變,還有,自定義對話框是做成的組件,應用于很多場合(有很多的界面用到此對話框);
//這是自定義的對話框,當事件是checkbox時,讓父界面做//出改變
Public class DialogBox implements ClickListener {
Public void onClick(event e){
}
}
//這是父界面,他彈出對話框
Public class ParentFrame extends ParentClass{
Public void popDialogBox(){
DialogBox dialogbox = new DialogBox(this) ;
}
}
解決方案一:
我把父界面的父類改變成自定義的父類,讓父界面繼承自定義的父類:
Public class DialogBox implements ClickListener{
Private Ojbect object = null ;
Private CheckBox checkbox = new CheckBox() ;
Public DialogBox(Ojbect object){
this.object = object ;
}
Public void onClick(event e){
If(e == checkbox){
//當事件是checkbox時,強制轉換成Custom調用//update方法
((Custom)object).update();
}
}
}
//這是自定義類,它繼承了ParentClass,并抽象了個update方//法
Public abstact CustomClass extends ParentClass{
Public abstract void update() ;
}
Public class ParentFrame extends CustomClass {
Public void popDialogBox(){
DialogBox dialogbox = new DialogBox(this) ;
}
Public void update(){
//父界面的更新操作
}
}
這個解決方案確實解決的問題,當自定義對話框點擊checkbox時,確實會使他的父界面發生改變,但他的缺點太大:必須繼承CustomClass才能具備這樣的功能,而且主要是因為他改變了繼承關系,在ParentFrame和ParentClass之間加了一層,這樣使耦合度加大了;而且每次都把自身的引用通過構造傳過去(new DialogBox(this)),在dialogbox那邊還要強行轉換回來,確實不是什么好辦法J
解決方案二:
//定義CustomListener接口
Public interface CustomListener (){
Public void update() ;
}
Public class DialogBox implements ClickListener{
Private Ojbect object = null ;
Private CheckBox checkbox = new CheckBox() ;
Public DialogBox(Ojbect object){
this.object = object ;
}
Public void onClick(event e){
If(e == checkbox){
//當事件是checkbox時,強制轉換成Custom調用//update方法
((CustomListener)object).update();
}
}
}
//實現了CustomListener接口
Public class ParentFrame extends ParentClass implements CustomListener {
Public void popDialogBox(){
DialogBox dialogbox = new DialogBox(this) ;
}
Public void update(){
//父界面的更新操作
}
}
這個解決方案也是解決了問題,尤其對第一解決方案而言,這個已經不會打亂繼承關系,但是還沒有脫離第二個缺陷;
解決方案三:
//定義Listener接口
Public interface CustomListener(){
Public void update() ;
}
//定義event接口
Public interface CustomEvent(){
Public void addCustomListener(CustomListener listener) ;
Public void removeCustomListener(CustomListener listner) ;
Public void notify() ;
}
Public class DialogBox implements ClickListener, CustomEvent {
Private List listenerList = new ArrayList() ;
Private CheckBox checkbox = new CheckBox() ;
Public DialogBox(Ojbect object){
this.object = object ;
}
Public void onClick(event e){
If(e == checkbox){
notify() ;
}
}
//注冊一個觀察者
Public void addCustomListener(CustomListener listener) {
listenerList.add(listener) ;
}
//刪除一個觀察者
Public void removeCustomListener(CustomListener listner){
listenerList.remove(listener) ;
}
//調用所以注冊的觀察者
Public void notify() {
If(listenerList != null && !( listenerList.isEmpty)){
for(int I = 0 ; I < listenerList.size() ; I ++){
((CustomListener)listenerList.get(i)).update();
}
}
}
}
//實現了CustomListener接口
Public class ParentFrame extends ParentClass implements CustomListener {
Public void popDialogBox(){
DialogBox dialogbox = new DialogBox() ;
dialogbox. addCustomListener((CustomListener)this) ;
}
Public void update(){
//父界面的更新操作
}
}
第三中解決方案才是觀察者模式是應用,這才是較為合理的方案;
觀察者模式應用前提是:有一個對象出發事件時,其他對象也發生改變;是個一對多的關系
在GWT中,在widget的方法remove是非常常用的,但請您好好注意一個小問題:
當你用循環remove時,請注意最好使用倒循環,因為如果你要是用正循環的話,remove一個widget后,他的下個widget就會到他的“位置”,例如:
int count = widgetPanel.getWidgetCount() ;
for(int i = 0 ; i < count ; i ++ )
{
widgetPanel.remove(i) ;
}
這樣肯定會出異常的;
因為當你remove掉第一個widget后,第二個widget就變成第一個widget了,所以,當你認為remove掉第二個時,其實是把原來的第三個widget給remove掉了;
解決方案:
1.倒循環:
int count = widgetPanel.getWidgetCount() ;
for(int i = count - 1 ; i >= 0 ; i -- )
{
widgetPanel.remove(i) ;
}
這樣就不會出現以上的情況:)
2.remove第一個;
int count = widgetPanel.getWidgetCount() ;
for(int i = 0 ; i < count ; i ++ )
{
widgetPanel.remove(0) ;
}
這種方法,也正說明了GWT轉換成javascript后的特性,它是根據remove的元素,在他父元素里的“位置”進行remove,這點是和Swing最大的區別,一定要注意喲:)