“人有悲歡離合,月有陰晴圓缺”,包括人在內(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)模式。
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)模式可以在一定程度上解決上述問題。