狀态模式(STATE),别名狀态對象(Objects for States),允許一個對象在其内部狀态改變時改變它的行為,看起來就像修改了它的類,屬于對象行為型模式。狀态模式通過将所有與特定狀态相關的行為封裝到一個或多個狀态對象中,當狀态改變時,其行為也會随着改變,進而簡化大量的條件判斷,使代碼邏輯更清晰,更易于維護。大千世界,可以看做各個狀态的轉換。人,生老病死;水,固液氣三态轉化;天氣,陰晴不定。就是這些狀态的變換構成了奇妙的世界。玩個遊戲都還分低中進階呢,是以狀态模式用途大大地。
一、使用場景
1、一個對象的行為取決于它的狀态,并且它必須在運作時根據狀态改變它的行為。俗話說小孩的臉,六月的天,說變就變。他高興的時候手舞足蹈,傷心的時候大哭大鬧,小孩的行為随着心情而改變。
2、一個操作中含有大量的多分支條件語句,且這些分支依賴于該對象的狀态。狀态模式将這些條件分支封裝到多個狀态類中,這些類可以獨立變化。
3、封裝狀态轉換的規則。狀态模式中,各狀态之間的轉換即可以由狀态類自己把握,也可以由環境類控制,集中而不失靈活。
二、UML圖
三、Java實作
package study.patterns.state;
/**
* 狀态模式:将一個對象在不同狀态下的不同行為封裝在一個個狀态類中,
* 通過設定不同的狀态對象可以讓環境對象擁有不同的行為,
* 而狀态轉換的細節對于用戶端而言是透明的,友善了用戶端的使用。
* @author qbg
* 此處示例由于對TCP協定了解不深,實作不是多恰當,望包涵!
*/
public class StatePattern {
public static void main(String[] args) {
TCPConnection connection = new TCPConnection();
connection.activeOpen();
connection.close();
}
}
/**
* TCP連接配接,維持一個TCP狀态對象,并将請求轉發給該對象。
*/
class TCPConnection{
private TCPState state;
/**
* 預設建立的TCP連接配接是關閉狀态
*/
public TCPConnection(){
state = TCPClosed.instance;
}
/**
* 主動發起打開連接配接請求
*/
public void activeOpen(){
state.activeOpen(this);
}
/**
* 被動接受打開連接配接請求
*/
public void passiveOpen(){
state.passiveOpen(this);
}
/**
* 關閉連接配接
*/
public void close(){
state.close(this);
}
/**
* 發送确認碼(ACK碼)
*/
public void acknowledge(){
state.acknowledge(this);
}
/**
* 發送連接配接請求
*/
public void send(){
state.send(this);
}
/**
* 改變TCP連接配接狀态
*/
public void changeState(TCPState state){
System.out.println(this.state+" ===> "+state);
this.state = state;
}
/**
* 處理流資料
*/
public void processOCtet(String stream){
System.out.println("傳輸流資料:"+stream);
}
}
/**
* TCP狀态抽象類,定義了狀态的公共行為,并針對所有委托給它的請求實作預設的行為。
*/
abstract class TCPState{
/**
* 傳輸請求的流資料(包含各種校驗碼)
*/
public void transmit(TCPConnection connection,String data){}
/**
* 主動發起打開連接配接請求
*/
public void activeOpen(TCPConnection connection){}
/**
* 被動接受打開連接配接請求
*/
public void passiveOpen(TCPConnection connection){}
/**
* 關閉連接配接
*/
public void close(TCPConnection connection){}
/**
* 發送确認碼(ACK碼)
*/
public void acknowledge(TCPConnection connection){}
/**
* 發送連接配接請求
*/
public void send(TCPConnection connection){}
/**
* 根據目前狀态,改變TCPConnection的TCP連接配接狀态
*/
public void changeState(TCPConnection connection,TCPState state){
connection.changeState(state);
}
}
/**
* TCP連接配接建立狀态,可以傳輸資料,關閉連接配接等
*/
class TCPEstablished extends TCPState{
/**
* 無狀态類,是以執行個體可以共享
*/
public static TCPState instance = new TCPEstablished();
@Override
public void transmit(TCPConnection connection, String data) {
connection.processOCtet(data);
}
/**
* 關閉連接配接并切換狀态
*/
@Override
public void close(TCPConnection connection) {
System.out.println("Send FIN,receive ACK of FIN");
changeState(connection, TCPClosed.instance);
}
public String toString(){
return "Established";
}
}
/**
* TCP連接配接關閉狀态,可以打開連接配接等
*/
class TCPClosed extends TCPState{
/**
* 無狀态執行個體,可以共享
*/
public static TCPState instance = new TCPClosed();
/**
* 主動建立連接配接,并改變狀态
*/
@Override
public void activeOpen(TCPConnection connection) {
System.out.println("Send SYN,receive SYN,ACK,etc.");
changeState(connection, TCPEstablished.instance);
}
/**
* 被動建立連接配接,并改變狀态
*/
@Override
public void passiveOpen(TCPConnection connection) {
changeState(connection, TCPListen.instance);
}
public String toString(){
return "Closed";
}
}
/**
* TCP監聽狀态,可以發送ACK,SYN,FIN等請求資料
*/
class TCPListen extends TCPState{
public static TCPState instance = new TCPListen();
/**
* 發送請求資料
*/
@Override
public void send(TCPConnection connection) {
changeState(connection, TCPEstablished.instance);
}
public String toString(){
return "Listen";
}
}
運作結果:
Send SYN,receive SYN,ACK,etc.
Closed ===> Established
Send FIN,receive ACK of FIN
Established ===> Closed
四、模式優缺點
優點:
1、将于特定狀态相關的行為局部化,并将不同狀态的行為分割開來。狀态模式将所有與某個特定狀态相關的行為封裝到一個狀态對象中,這樣通過添加新的子類可以很容易的增加新的狀态和轉換。
2、使狀态轉換顯示化。狀态模式中不同狀态之間的轉換是通過切換環境類中的變量來實作的,如TCPConnection類中的TCPState對象引用,而不是為多個變量指派,這樣確定狀态轉換的原子性,防止環境類Context内部狀态不一緻現象的發生。
3、State對象可以被共享。對于那些沒有内部狀态,隻有行為的輕量級State對象,各Context對象可以共享一個State對象,進而減少對象的數量。
缺點:
1、由于每個狀态對應一個對象,是以會導緻系統中類和對象的個數增加。
2、狀态模式的設計和實作比較複雜,增加系統的複雜度。