【設計模式基礎】行為模式 - 8 -狀態(State)

王曉斌發表於2014-03-11

1. 模式意圖

允許一個物件在其內部狀態改變時改變它的行為。物件看起來似乎是修改了它的類。

在很多情況下,一個物件的行為取決於一個或多個動態變化的屬性,這樣的屬性叫做狀態,這樣的物件叫做有狀態的物件。這樣的物件的狀態是從事先定義好的一系列值中取出的。當一個這樣的物件與外部事件產生互動時,其內部狀態就會改變,從而使得系統的行為也隨之發生變化。

適用性:

  • 一個物件的行為取決於它的狀態,並且它必須在執行時根據狀態改變它的行為。
  • 一個操作中含有龐大的多分支的條件語句,並且這些分支依賴於該物件的狀態。這個狀態通常用一個或多個列舉常量表示。通常,有多個操作包含這一相同的條件結構。State模式將每一個條件分之放入一個獨立的類中。這使得可以根據物件自身的情況將物件的狀態作為一個物件,這一物件可以不依賴於其他物件而獨立變化。

2. 模式定義


Context:            定義客戶感興趣的介面;維護一個ConcreteState子類的例項,這個例項定義當前狀態。

State:                 定義一個介面以封裝與Context的一個特定狀態相關的行為。

ConcreteState:每一個子類實現一個與Context的一個狀態相關的行為。


協作:

  • Context將與狀態相關的請求委託為當前的ConcreteState物件處理
  • Context可將自身作為一個引數傳遞給處理該請求的狀態物件。這使得狀態物件在必要時可訪問Context
  • Context是客戶使用的主要介面。客戶可用狀態物件來配置一個Context,一旦一個Context配置完畢,它的客戶不再需要直接與狀態物件打交道
  • Context或ConcreteState子類都可以決定哪個狀態是另外哪一個的後繼者,以及是在何種條件下進行狀態轉換

優點:

  • 它將與特定狀態相關的行為區域性化,並且將不同狀態的行為分隔開來
  • 它使得狀態轉換顯式化
  • State物件可被共享

缺點:

  • 狀態模式的使用或增加系統類和物件的個數
  • 狀態模式的結構和實現都比較複雜,如果使用不當將導致程式結構和程式碼的混亂

實現細節:

  • 誰定義狀態轉換: state模式不指定哪一個參與者定義狀態轉換準則。如果該準則是固定的,那麼它們可以在Context中完全實現;然而若讓State子類自身指定它們的後繼狀態以及何時進行轉換,通常更靈活更合適。這需要Context增加一個介面,讓State物件顯式的設定Context的當前狀態。用這種方法分散轉換邏輯可以很容易地定義新的State子類來修改和擴充套件該邏輯。這樣做的缺點是,一個State子類至少擁有一個其他子類的資訊,這就在各子類之間產生了實現依賴。
  • 建立和銷燬State物件: 究竟是(1)僅當需要State物件時才建立它們並隨後銷燬它們,還是(2)提前建立它們並且始終不銷燬它們。 當將要進入的狀態在執行時是不可知的,並且上下文不經常改變狀態時,第一種選擇較為可取。當狀態改變很頻繁時,第二張方法比較好,但是這種方法可能不太方便,因為Context必須儲存對所有可能會進入的那些狀態的引用。

3. 模式實現

3.1 C++實現State模式

class TCPOcterStream;
class TCPState;'

// Context
class TCPConnection
{
public:
    TCPConnection();

    void ActiveOpen();
    void PassiveOpen();
    void Close();
    void Send();
    void Acknowledge();
    void Synchronize();

    void ProcessOctet(TCPOctetStream*);

private:
    friend class TCPState;
    void ChangeState(TCPState*);
private:
    TCPState* _state;
};

TCPConnection::TCPConnection()
{
    _state = TCPClosed::Instance();
}
void TCPConnection::ChangeState(TCPState* s)
{
    _state = s;
}
void TCPConnection::ActiveOpen()
{
    _state->ActiveOpen(this);
}
void TCPConnection::PassiveOpen()
{
    _state->PassiveOpen(this);
}
void TCPConnection::Close()
{
    _state->Close(this);
}
void TCPConnection::Acknowledge()
{
    _state->Acknowledge(this);
}
void TCPConnection::Synchronize()
{
    _state->Synchronize(this);
}

// State
class TCPState
{
public:
    virtual void Transmit(TCPConnection*, TCPOctetStream*);
    virtual void ActiveOpen(TCPConnection*);
    virtual void PassiveOpen(TCPConnection*);
    virtual void Close(TCPConnection*);
    virtual void Synchronize(TCPConnection*);
    virtual void Acknowledge(TCPConnection*);
    virtual void Send(TCPConnection*);
protected:
    void ChangeState(TCPConnection*, TCPState*);
};

void TCPState::ChangeState(TCPConnection* t, TCPState* s)
{
    t->ChangeState(s);
}

// Sub State - Established
class TCPEstablishd : public TCPState
{
public:
    static TCPState* Instance();

    virtual void Transmit(TCPConnection*, TCPOctetStream*);
    virtual void Close(TCPConnection*);
};
void TCPEstablished::Transmit(TCPConnection* t, TCPOctetStream* o)
{
    t->ProcessOctet(o);
}
void TCPEstablished::Close(TCPConnection* t)
{
    // send FIN, receive ACK of FIN
    // ... ...
    ChangeState(t, TCPListen::Instance());
}

// Sub State - Closed
class TCPClosed : public TCPState
{
public:
    static TCPState* Instance();

    virtual void ActiveOpen(TCPConnection*);
    virtual void PassiveOpen(TCPConnection*);
};
void TCPClosed::ActiveOpen(TCPConnection* t)
{
    // send SYN, receive SYN, ACK, etc.
    // ... ...
    ChangeState(t, TCPEstablished::Instance());
}
void TCPClosed::PassiveOpen(TCPConnection* t)
{
    // ... ...
    ChangeState(t, TCPListen::Instance);
}



4. 模式應用





相關文章