小A:“要怎麼去決定是否使用狀態模式?”
大B:“在實際使用,類似開關一樣的狀態切換是很多的,但有時並不是那麼明顯,取決於你的經驗和對系統的理解深度。這裡要說的是‘開關切換狀態’和‘一般的狀態判斷’是有一些區別的,‘一般的狀態判斷’也是有if……elseif結構。”
例如:
if(which……1)state=“hello”;
elseif(which……2)state=“hi”;
elseif(which……3)state=“bye”;
大B:“這是一個‘一般的狀態判斷’,state值的不同是根據which變量來決定的,which和state沒有關係。”
如果改成:
if(state.euqals(“bye”))state=“hello”;
elseif(state.euqals(“hello”))state=“hi”;
elseif(state.euqals(“hi”))state=“bye”;
大B:“這就是‘開關切換狀態’,是將state的狀態從‘hello’切換到‘hi’,再切換到‘bye’;在切換到‘hello’,好象一個旋轉開關,這種狀態改變就可以使用State模式了。如果單純有上面一種將‘hello’——>‘hi’——>‘bye’——>‘hello’這一個方向切換,也不一定需要使用State模式,因爲State模式會建立很多子類,複雜化,但是如果又發生另外一個行爲:將上面的切換方向反過來切換,或者需要任意切換,就需要State了。”
請看下例:
publicclassContext{
privateColorstate=null;
publicvoidpush(){
//如果當前red狀態就切換到。
if(state……Color.red)state=Color.blue;
//如果當前blue狀態就切換到。
elseif(state……Color.blue)state=Color.green;
//如果當前black狀態就切換到。
elseif(state……Color.black)state=Color.red;
//如果當前green狀態就切換到。
elseif(state……Color.green)state=Color.black;
Samplesample=newSample(state);
sample.operate();
}
publicvoidpull(){
//與push狀態切換正好相反
if(state……Color.green)state=Color.blue;
elseif(state……Color.black)state=Color.green;
elseif(state……Color.blue)state=Color.red;
elseif(state……Color.red)state=Color.black;
Sample2sample2=newSample2(state);
sample2.operate();
}
}
大B:“在上例中,我們有兩個動作push推和pull拉,這兩個開關動作,改變了Context顏色,至此,我們就需要使用State模式優化它。另外注意:state的變化,只是簡單的顏色賦值,這個具體行爲是很簡單的,State適合巨大的具體行爲,因此,實際使用中也不一定非要使用State模式,這會增加子類的數目,簡單的變複雜。”
例如:銀行帳戶,經常會在Open狀態和Close狀態間轉換。
例如:經典的TcpConnection,Tcp的狀態有創建、偵聽、關閉三個,並且反覆轉換,其創建、偵聽、關閉的具體行爲不是簡單一兩句就能完成的,適合使用State。
例如:信箱POP帳號,會有四種狀態,startHaveUsernameAuthorizedquit,每個狀態對應的行爲應該是比較大的。適合使用State。
例如:在工具箱挑選不同工具,可以看成在不同工具中切換,適合使用State。如具體繪圖程序,用戶可以選擇不同工具繪製方框、直線、曲線,這種狀態切換可以使用State。