文章

狀態模式 - State Pattern

用途

透過改變狀態來改變行為,讓每個狀態行為獨立易於添加、修改

classDiagram
  ConcreteStateA ..|> IState
  ConcreteStateB ..|> IState
  IState --o Context
  Client ..> Context
  note for Client "Create context then use request"
  namespace State {
    class IState{
      <<Interface>>
      +HandleRequest(Context)
    }
    class ConcreteStateA{
      +HandleRequest(Context)
    }
    class ConcreteStateB{
      +HandleRequest(Context)
    }
    class Context{
      -State state
      +ChangeState(IState)
      +Request()
    }
  }
  class Client{
    +Operation()
  }

例子

當談到狀態模式(State Pattern)時,我們可以使用簽核的情境來解釋
在許多組織或系統中,文件或任務需要經過一系列的簽核程序
每個簽核階段都有不同的狀態和操作
這個情境可以很好地展示狀態模式的應用。

State

1
2
3
4
public interface State
{
    void HandleRequest(Context context);
}

ConcreteState

1
2
3
4
5
6
7
8
9
public class ConcreteStateA : State
{
    public void HandleRequest(Context context)
    {
        Console.WriteLine("HandleRequest in ConcreteStateA");
        // 改變狀態為ConcreteStateB
        context.ChangeState(new ConcreteStateB());
    }
}
1
2
3
4
5
6
7
8
9
public class ConcreteStateB : State
{
    public void HandleRequest(Context context)
    {
        Console.WriteLine("HandleRequest in ConcreteStateB");
        // 改變狀態為ConcreteStateA
        context.ChangeState(new ConcreteStateA());
    }
}

Context

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class Context
{
    private State currentState;

    public Context()
    {
        // 初始狀態為ConcreteStateA
        currentState = new ConcreteStateA();
    }

    public void ChangeState(State state)
    {
        currentState = state;
    }

    public void Request()
    {
        // 呼叫當前狀態的操作
        currentState.HandleRequest(this);
    }
}

Client

1
2
3
4
5
// 使用範例
Context context = new Context();
context.Request();  // 輸出: HandleRequest in ConcreteStateA
context.Request();  // 輸出: HandleRequest in ConcreteStateB
context.Request();  // 輸出: HandleRequest in ConcreteStateA

延伸

本文章以 CC BY 4.0 授權