---
# System prepended metadata

title: State

---

## State
> 讓物件的外顯行為隨內部狀態的改變而改變，彷彿連類別也變了似的

### 時機
* 當物件行為取決於它的狀態，連執行期行為也得隨狀態而改變時。
* 若是某些操作內，依據物件狀態而做的條件判斷式太過龐大時。

### 結構
![](https://i.imgur.com/vvpVmMc.png)

### 參與者
* Context
  -制定外界改興趣的介面
  -持有一個ConcreteState子類別的物件個體，代表現行狀態
* State
  -此介面負責封裝當Context處於特定狀態時所該展現的行為
* ConcreteState
  -每一個子類別都針對某一種Context狀態實作出該展現的行為
  
```ruby=
class Context

  attr_accessor :state
  private :state


  def initialize(state)
    transition_to(state)
  end


  def transition_to(state)
    puts "Context: Transition to #{state.class}"
    @state = state
    @state.context = self
  end



  def request1
    @state.handle1
  end

  def request2
    @state.handle2
  end
end


class State
  attr_accessor :context


  def handle1
    raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"
  end


  def handle2
    raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"
  end
end


class ConcreteStateA < State
  def handle1
    puts 'ConcreteStateA handles request1.'
    puts 'ConcreteStateA wants to change the state of the context.'
    @context.transition_to(ConcreteStateB.new)
  end

  def handle2
    puts 'ConcreteStateA handles request2.'
  end
end

class ConcreteStateB < State
  def handle1
    puts 'ConcreteStateB handles request1.'
  end

  def handle2
    puts 'ConcreteStateB handles request2.'
    puts 'ConcreteStateB wants to change the state of the context.'
    @context.transition_to(ConcreteStateA.new)
  end
end

# The client code.

context = Context.new(ConcreteStateA.new)
context.request1
context.request2
```

### 合作方式
* Context將與狀態有關的訊息委託給目前持的ConcreteState物件去處理
* Context把自己列為參數，傳給處理訊息的State物件，以便後者在必要時能存取得到自己
* Context是主要的對外窗口。客戶碼可用State物件來設定Context組態，設定好後，就不在直接插手State物件
* 可令Context或者ConcreteState的子類別決定在什麼情況下該切換成什麼狀態

### 優點
1. 集中處理與狀態相依的行為並予以切割（易於新增狀態）。也可以使用資料值的方式儲存，但會造成許多判斷式。
2. 凸顯狀態轉移邏輯。以Context的角度來看，狀態轉移應該是不可再細分的atomic動作;觀念上應該是重設**一個**變數（Context的State物件變數），不該是好幾個變數設來設去。
3. 狀態物件可以共用。如果State物件不含個體變數，Context就可共用State物件（此時State物件就相當於沒有內在狀態或者說只有行為的Flyweight物件）