<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>


    posts - 15,  comments - 34,  trackbacks - 27
    在對一個J2EE項目的重構、增加新功能的過程中,對客戶端GUI程序,我們使用了State模式。結果顯示,該模式的使用,不但減少了客戶端GUI程序的程序規模(LOC),而且,該部分的開發及單元測試時間大大減少,同時,在集成測試中發現的缺陷數量比使用該模式前平均減少了3倍。本文就該項目中使用State模式的方式進行介紹。

    引言
    在分層軟件體系結構中,服務端程序關注于實現業務邏輯,客戶端程序則包含用戶界面。服務端程序由客戶端程序調用,其請求、響應模式在設計時已經確定,運行時出現問題的概率較小。相反,客戶端程序與用戶直接交互,雖然有正確規定的操作順序或模式,但是用戶的操作是不可預知的,程序必須處理各種操作錯誤、加上數據輸入有效驗證等要求,使得客戶端程序的開發成本上升。

    因而,一旦有經過充分測試的、甚至是通過驗收的用戶交互程序GUI,應該盡可能的重用該GUI,以提高軟件的可靠性、可維護性。

    在對一個J2EE項目的重構、增加新功能的過程中,對客戶端GUI程序,我們使用了State模式。結果顯示,該模式的使用,不但減少了客戶端GUI程序的程序規模(LOC),而且,該部分的開發及單元測試時間大大減少,同時,在集成測試中發現的缺陷數量比使用該模式前平均減少了3倍。本文就該項目中使用State模式的方式進行介紹。

    1. State模式
    首先,先簡單介紹一下State模式。

    該模式是指在對象的內部狀態改變時改變對象的行為【1】。其結構如圖1所示。

    圖1 State模式結構
    圖1 State模式結構

    模式中各個參與者職責簡介如下:

    • Context:用戶對象,擁有一個State類型的成員,以標識對象的當前狀態;
    • State:接口或基類,封裝與Context的特定狀態相關的行為;
    • ConcreteState:接口實現類或子類,實現了一個與Context某個狀態相關的行為。

    運行時,Context將與狀態相關的請求委托給當前的ConcreteState對象處理。關于State模式更詳盡的介紹,請參閱參考文獻1。

    2. 客戶端應用
    本模式的目標是分離客戶端軟件中的變化部分與不變部分,以使得變化的部分可獨立于不變的部分,有利于擴充新的功能,也有利于維護。

    在項目中,對于客戶端GUI的重用有兩種方式。

    • 方式1適用于:相同數據集合,不同操作模式;此時,在GUI中定義客戶端數據處理驗證邏輯,不同的狀態對象封裝了不同的操作模式;
    • 方式2適用于:不同數據集合,相同操作模式;此時,在狀態對象中定義客戶端數據處理驗證邏輯,不同的狀態對象封裝了不同的數據集合操作。

    2.1 類型1: Read-Only & Normal
    2.1.1 動機

    客戶端GUI接受用戶輸入,經過數據有效性驗證,然后將數據傳輸到服務端,服務端檢查業務邏輯有效性,保存數據;但是在特定情況下(比如數據已經存在、且只能經歷一次輸入),依據客戶端GUI所操作數據的狀態,業務邏輯要求數據為只讀,即客戶端只具有顯示數據的功能,并不能改變服務器上的數據。

    一般地,編程實現時,會在GUI程序中加入判斷數據是否應該為只讀的邏輯判斷語句。如果針對相同的數據集合(Model),有多個客戶端GUI(View),就需要在每個程序中加入該判斷。如此降低了程序的可維護性,決定數據是否為只讀的這樣一個業務邏輯將分散在程序中多處,不易維護,在業務邏輯發生改變時,易造成不一致。

    我們可以將變化部分(在Normal和Read-Only狀態下不同的部分)從GUI中抽取出來,分別用不同的類來表示,這樣,當GUI的狀態發生改變時,只需要改變其對狀態對象的引用即可,狀態相關操作委托給狀態對象去完成。

    2.1.2 適用性

    本類型適用環境:相同數據集合,不同操作模式。即特定的GUI根據操作上下文環境,改變其響應模式,根據數據是否可編輯,分為兩種狀態Read-Only State、 Normal State。

    2.1.3 結構(圖2)

    圖2 相同數據集合,不同操作模式
    圖2  相同數據集合,不同操作模式

    2.1.4 參與者

    • ClientStateChangeable:客戶端GUI提供給State對象的操作接口,使得State對象可以訪問GUI的成員,以完成該狀態相關操作;
      • getChangeableComponents():返回在狀態轉換為Read-Only時,不可編輯的控件Collection;
      • saveChangeToServer():在可編輯狀態時,將客戶端數據保存到服務端。
    • AClientGUI:完成圖1中的Context功能,即其狀態要進行改變的客戶端GUI;維護ClientState的一個實例(state);
      • init():將this引用作為參數,調用state.setComponents(this) 以設置可變控件的初始狀態;
      • okButtonActionPerformed(e:ActionEvent):用戶完成操作后,本方法可作為 "OK"按鈕控件的ActionListener方法,調用state.action(this) 以完成本操作。
    • ClientState:State接口,封裝與客戶端GUI某個特定狀態相關的行為;
      • setComponents(gui:ClientStateChangeable):設置參數gui指定的客戶端GUI的控件狀態;
      • action(gui:ClientStateChangeable):完成數據保存功能。
    • ClientNormalState:可編輯狀態子類,實現ClientState接口;
      • setComponents(gui:ClientStateChangeable):調用參數gui指定的客戶端GUI的getChangeableComponents()獲取控件Collection,然后遍歷設置各控件狀態為可編輯;
      • action(gui:ClientStateChangeable):調用參數gui指定的客戶端GUI的saveChangeToServer()完成數據保存功能。
    • ClientReadOnlyState:只讀狀態子類,實現ClientState接口;
      • setComponents(gui:ClientStateChangeable):調用參數gui指定的客戶端GUI的getChangeableComponents()獲取控件Collection,然后遍歷設置各控件狀態為ReadOnly;
      • action(gui:ClientStateChangeable):空方法,本狀態下無數據變化,無須保存。

    2.1.5 代碼示例

    ClientStateChangeable接口:


    
    public interface ClientStateChangeable {	
    	/**
    	 * To get all changeable components in the GUI object. 
    	 * @return Collection contains Component objects. 
    	 */
    	Collection getChageableComponents();
    	
    	/**
    	 * To save data to server.
    	 */
    	void saveChangeToServer();
    }
    

    AClientGUI類:


    
    public class AClientGUI extends JPanel implements ClientStateChangeable{
    	//… 	
    	private ClientState state = null;
    
    public DesignStep1View(ClientState state){
    //…			
    this.state = state;
    this.state.setComponents(this);
    	}
    	
    	private void okButton_actionPerformed(ActionEvent e){
    		state.action(this);	//save data
    	}
    
    	public Collection getChageableComponents() {
    		Collection dataComponents = new ArrayList();		
    		dataComponents.add(jComboBoxESEPattern);
    		//…			
    		return dataComponents;
    	}
    
    	public void saveChangeToServer() {
    		//…	
    	}
    }
    

    ClientState接口:

    public interface ClientState { /** * To set components' state in the GUI. * @param gui a GUI object which implements StateChangeable interface. */ void setComponents(ClientStateChangeable gui); /** * when user click OK-Button in a GUI, the GUI will call this method. * @param gui a GUI object which implements StateChangeable interface. */ void action(ClientStateChangeable gui); }

    ClientNormalState類:


    olor="#CCCCCC">
    
    public class ClientNormalState implements ClientState {
    	/**
    	 * 正常狀態下, 各個控件默認為可編輯的, 所以不用做任何更改
    	 */
    	public void setComponents(ClientStateChangeable gui) {}
    
    	/** 
    	 * 正常狀態下, 需要將用戶所作修改保存到服務端 
    	 */
    	public void action(ClientStateChangeable gui) {
    		gui.saveChangeToServer();
    	}
    }
    

    ClientReadOnlyState類:


    
    public class ClientReadOnlyState implements ClientState {
    	/**
    	 * 設置GUI的數據控件為Read-Only
    	 */
    public void setComponents(ClientStateChangeable gui) {
    		Collection components = gui.getChageableComponents();
    		Iterator iter = components.iterator();
    		while(iter.hasNext()){
    			JComponent jc = (JComponent)iter.next();
    			jc.setEnabled(false);			
    			String toolTip = jc.getToolTipText();
    			String addedTip = "只讀狀態";
    			if(toolTip == null)toolTip = addedTip;
    			else toolTip += ". " + addedTip;
    			jc.setToolTipText(toolTip); 
    		}
    	}
    
    	/**
    	 * GUI處于Read-Only狀態, 無需將數據保存到server端	
    	 */
    	public void action(ClientStateChangeable gui) {}
    }
    

    2.2 類型2:(Reuse GUI)
    2.2.1 動機

    當多個客戶端GUI布局、控件類型很相似,所完成的任務也相似時,只需要經過精心設計,將這些GUI的展示形式統一起來,同一個GUI可以用到多個場景中,達到重用的目的。此時,這些不同任務需要操作不同的數據集合。

    可以在GUI類中實現這些不同數據集合的操作,但是這會給程序維護帶來麻煩。首先,屬于不同邏輯的數據操作出現在同一類文件中,造成邏輯混亂、程序規模增大,不易于調試;其次,要將GUI用于新的數據集合時,只能在相同文件中增加新的代碼,此時,該程序的可維護性降低,尤其是新的工作由其他程序員完成時,要理解原有代碼是很費力的。

    和2.1.1節中提到的解決方法類似:將變化的部分和不變部分分離開來,使得變化的部分可以獨立修改、擴充。具體地,則是將數據集合相關操作從GUI程序中抽取出來,定義一個所有數據集合操作的接口(即:狀態接口),不同地數據集合操作作為該接口的一個實現類存在。這樣,每個數據集合都獨立的封裝于一個狀態對象內;而且,要對新的數據使用該GUI,只需要定義新的狀態接口實現類即可,無須修改已有類,甚至不關心已有的狀態。

    2.2.2 適用性

    本類型適用環境:不同的數據集合,相同的操作模式。即不變化的客戶端GUI,將不同的數據集合操作委托給變化的狀態對象去完成。

    2.2.3 結構(圖3)

    圖3 不同數據集合,相同操作模式
    圖3 不同數據集合,相同操作模式

    2.2.4 參與者

    • InvariableGUI:本身不發生變化的客戶端GUI類,維護一個對VariableDataState的引用state,將數據相關操作委托給該引用對象 ;
      • saveChangeToServer():調用state.processData(this)完成數據相關操作;
    • VariableDataState:State接口,封裝與數據相關操作的行為;
      • ProcessData(gui:InvariableGUI):調用參數gui的成員獲取數據并完成處理;
    • DataState1、DataState2、 … … DataStateN:狀態子類,實現VariableDataState接口,封裝了特定某一類數據集合的操作,可以根據不同的數據集合定義多個VariableDataState接口的狀態類,從而實現了對InvariableGUI的重用。

    本類型的實現代碼在這里就不列出了,參照2.1.5節中的代碼,很容易的就可實現本類型的結構。

    2.3 綜合以上兩種類型
    可以將以上兩種類型結合起來使用,即實現了客戶端軟件的數據集合方面對GUI的重用,也實現了操作模式方面對GUI的重用。

    程序實現時,可以由GUI類分別維護一個ClientState的引用和一個VariableDataState的引用:

    • 初始化GUI類時,GUI的構造器調用ClientState對象的setComponents()方法設置控件的狀態;
    • 用戶提交操作時,GUI調用ClientState對象的action()方法,如圖2所示,該方法使用傳遞的gui參數回調GUI的saveChangeToServer()方法,而saveChangeToServer()方法則按照圖3所示,調用VariableDataState引用的狀態對象的processData()方法完成數據操作。

    3 總結
    本文介紹的State模式應用于多類型數據、多操作模式的客戶端軟件,可以取得明顯的效果;但如果客戶端類和狀態都很少時,使用本模式,反而增加了客戶端類數量,增加了體系結構的復雜性,此時,可以使用繼承方式的類體系來實現重用,無須使用State狀態對象的委托操作和回調操作。

    posted on 2005-02-05 20:09 jacky 閱讀(393) 評論(0)  編輯  收藏 所屬分類: Design Patten

    只有注冊用戶登錄后才能發表評論。


    網站導航:
     
    <2025年5月>
    27282930123
    45678910
    11121314151617
    18192021222324
    25262728293031
    1234567

    常用鏈接

    留言簿(10)

    隨筆檔案

    文章分類

    文章檔案

    相冊

    收藏夾

    java

    搜索

    •  

    最新評論


    主站蜘蛛池模板: 中文国产成人精品久久亚洲精品AⅤ无码精品 | 免费观看国产精品| 国产黄色片在线免费观看| 久久狠狠爱亚洲综合影院| 久久精品国产免费观看三人同眠| 亚洲国产综合专区电影在线| 性色午夜视频免费男人的天堂| 亚洲欧洲精品无码AV| 在线看片免费人成视频福利| 亚洲成av人影院| 7m凹凸精品分类大全免费| 亚洲精品国产成人中文| 114一级毛片免费| 亚洲日韩国产AV无码无码精品| 日韩在线看片免费人成视频播放| 日韩在线视精品在亚洲| 亚洲爱情岛论坛永久| 日韩视频免费在线观看| 水蜜桃亚洲一二三四在线| www.免费在线观看| 亚洲男同gay片| 免费又黄又爽又猛的毛片| 精品国产污污免费网站入口| 日产亚洲一区二区三区| 无码av免费毛片一区二区| 国产精品亚洲专区无码唯爱网| 亚洲国产成人a精品不卡在线| a毛片免费播放全部完整| 亚洲综合久久1区2区3区| 老司机永久免费网站在线观看| 国产97视频人人做人人爱免费| 亚洲成AV人片在线观看ww| 波多野结衣在线免费观看| 国产成人高清亚洲一区久久 | 成人妇女免费播放久久久| 久久精品无码一区二区三区免费| 国产精品亚洲精品| APP在线免费观看视频| 中文字幕亚洲第一在线| 国产美女无遮挡免费视频| 手机看片国产免费永久|