天天看點

用State模式建立向導的實踐。。。

向導就是類似于安裝軟體時,一大堆下一步的那個窗體。每一個上一步下一步意味着窗體上的控件需要改變,相關的按鈕的功能等也需要改變。在制作一個向導時,最初設計中,我用的enum來表示每一個步驟。比如:

switch(stepEnum) 

case StepEnum.FirstStep: 

    //some work 

    break; 

case StepEnum.SecondStep: 

    break: 

//... 

default: 

    //... 

}

這樣的設計,使得整個代碼中充斥着大量的switch...case語句,并且使得每個步驟涉及到的控件布局,邏輯處理等代碼混在一起。很是醜陋,無法忍受。于是我想用試着用state模式來除掉這些壞掉的味道。

State模式用[GOF]的話來說,使允許一個對象在其内部狀态改變時改變它的行為。我定義一個抽象的步驟類來取代原有的枚舉結構,各步驟繼承與這個抽象類。其定義如下:

public abstract class InitWizardStepState 

        public abstract void AddControlToContainer(Control container); 

        public abstract bool CouldGoToNext(); 

        public abstract InitWizardStepState GoToNextStep(); 

        public abstract InitWizardStepState GoToPreStep(); 

        public abstract bool IsFirstStep { get;} 

        public abstract bool IsLastStep { get;} 

通過這樣的設計,将每一個步驟的邏輯判斷和UI設計都封裝在了StepState中。避免了在主視窗中使用枚舉類來判斷各個操作。簡化了主視窗的代碼,實作了相關的隔離,除掉了壞掉的味道。同時,利用單件模式,降低反複上一步,下一步付出的代價。基本達到了目的。

但是實踐就是實踐,沒有經典問題那麼的純粹,有些問題很是折磨人。比如步驟轉換的控制是由誰控制。步驟轉換并不是一個簡單的由1-->2-->3-->...的過程。而根據使用者輸入和選擇的不同,可能存在1-->3-->...這樣的路徑,也可能有1-->2(1)-->3-->...這樣的路徑。設計中是将狀态的轉移控制封裝在了InitWizardStepState類中(使用GoToNextStep和GoToPreStep來控制)。比如:在1步驟是擷取需要轉移和需要删除的檔案清單,2步驟處理轉移檔案,3步驟處理删除檔案。如果1步驟中,使用者并沒有輸入轉移檔案,就可以跳過2直接進到3中。直接封裝在步驟中可以使得這種處理可以在内部完成。但我越來越覺得這不是一個良好的決定。因為并不符合開閉原則。如果我需要建立一個新的向導,這個向導的次序和相關處理與老步驟不同。我如果還想使用原先的步驟類,我必須修改裡面的邏輯,而并不是利用繼承建立新的步驟即可。說明這個設計不夠良好。

導緻這個問題出現的原因,我想是因為在步驟轉換是存在着資料的轉移.比如在1步驟中獲得了某個路徑,在2步驟中需要獲得這個路徑,就将路徑需要由步驟1傳個步驟2。這其實就與state模式的應用範圍産生了偏差。在state模式中,要求作為state的對象可以不依賴于其他對象而獨立變化。是以我一直不确定我所謂的state是不是真正的state。

在下一步工作中,想繼續改造上面的結構。即把各個步驟所需的(輸入和輸出的資料)放在一個類中,作為一個context存在。比如:以上面的轉移檔案和删除檔案為例,建立context如下:

public class Context 

        public string[] deleteFileList; 

        public string[] moveFileList; 

然後将決定上下步驟的部分從StepState中提取出來。放在主視窗中完成。進一步降低了步驟類之間的耦合。同時增加各步驟類于Context之間的聯系。比如:

将public abstract void AddControlToContainer(Control container);

改為public abstract void AddControlToContainer(Control container,Context context);

這樣可以更好的保持可擴充性和可重用性。

本文轉自 duguguiyu 51CTO部落格,原文連結:http://blog.51cto.com/duguguiyu/363383,如需轉載請自行聯系原作者

繼續閱讀