鍍金池/ 教程/ Java/ 處理對象的多種狀態(tài)及其相互轉換——狀態(tài)模式(一)
請求發(fā)送者與接收者解耦——命令模式(四)
對象間的聯(lián)動——觀察者模式(三)
算法的封裝與切換——策略模式(三)
請求發(fā)送者與接收者解耦——命令模式(三)
遍歷聚合對象中的元素——迭代器模式(四)
請求的鏈式處理——職責鏈模式(二)
自定義語言的實現(xiàn)——解釋器模式(五)
操作復雜對象結構——訪問者模式(一)
處理對象的多種狀態(tài)及其相互轉換——狀態(tài)模式(一)
處理對象的多種狀態(tài)及其相互轉換——狀態(tài)模式(三)
操作復雜對象結構——訪問者模式(二)
協(xié)調(diào)多個對象之間的交互——中介者模式(二)
算法的封裝與切換——策略模式(四)
請求發(fā)送者與接收者解耦——命令模式(六)
撤銷功能的實現(xiàn)——備忘錄模式(二)
算法的封裝與切換——策略模式(一)
遍歷聚合對象中的元素——迭代器模式(五)
模板方法模式深度解析(三)
協(xié)調(diào)多個對象之間的交互——中介者模式(五)
自定義語言的實現(xiàn)——解釋器模式(三)
處理對象的多種狀態(tài)及其相互轉換——狀態(tài)模式(六)
遍歷聚合對象中的元素——迭代器模式(三)
操作復雜對象結構——訪問者模式(四)
遍歷聚合對象中的元素——迭代器模式(一)
算法的封裝與切換——策略模式(二)
請求的鏈式處理——職責鏈模式(一)
遍歷聚合對象中的元素——迭代器模式(二)
操作復雜對象結構——訪問者模式(三)
對象間的聯(lián)動——觀察者模式(六)
對象間的聯(lián)動——觀察者模式(五)
請求發(fā)送者與接收者解耦——命令模式(一)
自定義語言的實現(xiàn)——解釋器模式(六)
自定義語言的實現(xiàn)——解釋器模式(一)
模板方法模式深度解析(一)
撤銷功能的實現(xiàn)——備忘錄模式(一)
處理對象的多種狀態(tài)及其相互轉換——狀態(tài)模式(五)
請求的鏈式處理——職責鏈模式(三)
遍歷聚合對象中的元素——迭代器模式(六)
撤銷功能的實現(xiàn)——備忘錄模式(三)
處理對象的多種狀態(tài)及其相互轉換——狀態(tài)模式(四)
處理對象的多種狀態(tài)及其相互轉換——狀態(tài)模式(二)
協(xié)調(diào)多個對象之間的交互——中介者模式(四)
對象間的聯(lián)動——觀察者模式(二)
請求發(fā)送者與接收者解耦——命令模式(二)
自定義語言的實現(xiàn)——解釋器模式(四)
對象間的聯(lián)動——觀察者模式(四)
撤銷功能的實現(xiàn)——備忘錄模式(五)
自定義語言的實現(xiàn)——解釋器模式(二)
協(xié)調(diào)多個對象之間的交互——中介者模式(三)
協(xié)調(diào)多個對象之間的交互——中介者模式(一)
撤銷功能的實現(xiàn)——備忘錄模式(四)
模板方法模式深度解析(二)
撤銷功能的實現(xiàn)——備忘錄模式(五)
請求發(fā)送者與接收者解耦——命令模式(五)
請求的鏈式處理——職責鏈模式(四)

處理對象的多種狀態(tài)及其相互轉換——狀態(tài)模式(一)

“人有悲歡離合,月有陰晴圓缺”,包括人在內(nèi),很多事物都具有多種狀態(tài),而且在不同狀態(tài)下會具有不同的行為,這些狀態(tài)在特定條件下還將發(fā)生相互轉換。就像水,它可以凝固成冰,也可以受熱蒸發(fā)后變成水蒸汽,水可以流動,冰可以雕刻,蒸汽可以擴散。我們可以用UML狀態(tài)圖來描述 H2O 的三種狀態(tài),如圖所示:

http://wiki.jikexueyuan.com/project/design-pattern-behavior/images/1358692722_1117.jpg" alt="H2O的三種狀態(tài)(未考慮臨界點)" />

在軟件系統(tǒng)中,有些對象也像水一樣具有多種狀態(tài),這些狀態(tài)在某些情況下能夠相互轉換,而且對象在不同的狀態(tài)下也將具有不同的行為。為了更好地對這些具有多種狀態(tài)的對象進行設計,我們可以使用一種被稱之為狀態(tài)模式的設計模式,本章我們將學習用于描述對象狀態(tài)及其轉換的狀態(tài)模式。

銀行系統(tǒng)中的賬戶類設計

Sunny 軟件公司欲為某銀行開發(fā)一套信用卡業(yè)務系統(tǒng),銀行賬戶(Account)是該系統(tǒng)的核心類之一,通過分析,Sunny 軟件公司開發(fā)人員發(fā)現(xiàn)在該系統(tǒng)中,賬戶存在三種狀態(tài),且在不同狀態(tài)下賬戶存在不同的行為,具體說明如下:

(1) 如果賬戶中余額大于等于 0,則賬戶的狀態(tài)為正常狀態(tài)(Normal State),此時用戶既可以向該賬戶存款也可以從該賬戶取款;

(2) 如果賬戶中余額小于 0,并且大于 -2000,則賬戶的狀態(tài)為透支狀態(tài)(Overdraft State),此時用戶既可以向該賬戶存款也可以從該賬戶取款,但需要按天計算利息;

(3) 如果賬戶中余額等于 -2000,那么賬戶的狀態(tài)為受限狀態(tài)(Restricted State),此時用戶只能向該賬戶存款,不能再從中取款,同時也將按天計算利息;

(4) 根據(jù)余額的不同,以上三種狀態(tài)可發(fā)生相互轉換。

Sunny 軟件公司開發(fā)人員對銀行賬戶類進行分析,繪制了如圖所示 UML 狀態(tài)圖:

http://wiki.jikexueyuan.com/project/design-pattern-behavior/images/1358692727_5983.jpg" alt="銀行賬戶狀態(tài)圖" />

在圖中,NormalState 表示正常狀態(tài),OverdraftState 表示透支狀態(tài),RestrictedState 表示受限狀態(tài),在這三種狀態(tài)下賬戶對象擁有不同的行為,方法 deposit() 用于存款,withdraw() 用于取款,computeInterest() 用于計算利息,stateCheck() 用于在每一次執(zhí)行存款和取款操作后根據(jù)余額來判斷是否要進行狀態(tài)轉換并實現(xiàn)狀態(tài)轉換,相同的方法在不同的狀態(tài)中可能會有不同的實現(xiàn)。為了實現(xiàn)不同狀態(tài)下對象的各種行為以及對象狀態(tài)之間的相互轉換,Sunny 軟件公司開發(fā)人員設計了一個較為龐大的賬戶類 Account,其中部分代碼如下所示:

class Account {
    private String state; //狀態(tài)
    private int balance; //余額
    ......

    //存款操作  
    public void deposit() {
        //存款
        stateCheck();   
    }

    //取款操作
    public void withdraw() {
        if (state.equalsIgnoreCase("NormalState") || state.equalsIgnoreCase("OverdraftState ")) {
            //取款
            stateCheck();
        }
        else {
            //取款受限
        }
    }

    //計算利息操作
    public void computeInterest() {
        if(state.equalsIgnoreCase("OverdraftState") || state.equalsIgnoreCase("RestrictedState ")) {
            //計算利息
        }
    }

    //狀態(tài)檢查和轉換操作
    public void stateCheck() {
        if (balance >= 0) {
            state = "NormalState";
        }
        else if (balance > -2000 && balance < 0) {
            state = "OverdraftState";
        }
        else if (balance == -2000) {
            state = "RestrictedState";
        }
        else if (balance < -2000) {
            //操作受限
        }
    }
    ......
}

分析上述代碼,我們不難發(fā)現(xiàn)存在如下幾個問題:

(1) 幾乎每個方法中都包含狀態(tài)判斷語句,以判斷在該狀態(tài)下是否具有該方法以及在特定狀態(tài)下該方法如何實現(xiàn),導致代碼非常冗長,可維護性較差;

(2) 擁有一個較為復雜的 stateCheck() 方法,包含大量的 if…else if…else… 語句用于進行狀態(tài)轉換,代碼測試難度較大,且不易于維護;

(3) 系統(tǒng)擴展性較差,如果需要增加一種新的狀態(tài),如凍結狀態(tài)(Frozen State,在該狀態(tài)下既不允許存款也不允許取款),需要對原有代碼進行大量修改,擴展起來非常麻煩。

為了解決這些問題,我們可以使用狀態(tài)模式,在狀態(tài)模式中,我們將對象在每一個狀態(tài)下的行為和狀態(tài)轉移語句封裝在一個個狀態(tài)類中,通過這些狀態(tài)類來分散冗長的條件轉移語句,讓系統(tǒng)具有更好的靈活性和可擴展性,狀態(tài)模式可以在一定程度上解決上述問題。