旧游无处不堪寻
无寻处,惟有少年心
设计模式-状态

状态模式(State Pattern)是一种行为型设计模式,让你能在一个对象的内部状态变化时改变其行为,使其看上去就像改变了自身所属的类一样。

解释


状态模式与有限状态机的概念紧密相关。

其主要思想是程序在任意时刻仅可处于几种有限的状态中。在任何一个特定状态中,程序的行为都不相同,且可瞬间从一个状态切换到另一个状态。不过,根据当前状态,程序可能会切换到另外一种状态,也可能会保持当前状态不变。这些数量有限且预先定义的状态切换规则被称为转移。

状态机通常由众多条件运算符(if 或 switch)实现,可根据对象的当前状态选择相应的行为。”状态”通常只是对象中的一组成员变量值。

状态模式 UML


适用场景


  1. 如果对象需要根据自身当前状态进行不同行为,同时状态的数量非常多且与状态相关的代码会频繁变更的话,可使用状态模式
  2. 如果某个类需要根据成员变量的当前值改变自身行为,从而需要使用大量的条件语句时,可使用该模式
  3. 当相似状态和基于条件的状态机转换中存在许多重复代码时,可使用状态模式

代码示例


using System;
namespace StatePatternDemo
{
class Context
{
// A reference to the current state of the Context.
private State _state = null;

public Context(State state)
{
this.TransitionTo(state);
}

// The Context allows changing the State object at runtime.
public void TransitionTo(State state)
{
Console.WriteLine($"Context: Transition to {state.GetType().Name}.");
this._state = state;
this._state.SetContext(this);
}

// The Context delegates part of its behavior to the current State
// object.
public void Request1()
{
this._state.Handle1();
}

public void Request2()
{
this._state.Handle2();
}
}

// The base State class declares methods that all Concrete State should
// implement and also provides a backreference to the Context object,
// associated with the State. This backreference can be used by States to
// transition the Context to another State.
abstract class State
{
protected Context _context;

public void SetContext(Context context)
{
this._context = context;
}

public abstract void Handle1();

public abstract void Handle2();
}

// Concrete States implement various behaviors, associated with a state of
// the Context.
class ConcreteStateA : State
{
public override void Handle1()
{
Console.WriteLine("ConcreteStateA handles request1.");
Console.WriteLine("ConcreteStateA wants to change the state of the context.");
this._context.TransitionTo(new ConcreteStateB());
}

public override void Handle2()
{
Console.WriteLine("ConcreteStateA handles request2.");
}
}

class ConcreteStateB : State
{
public override void Handle1()
{
Console.Write("ConcreteStateB handles request1.");
}

public override void Handle2()
{
Console.WriteLine("ConcreteStateB handles request2.");
Console.WriteLine("ConcreteStateB wants to change the state of the context.");
this._context.TransitionTo(new ConcreteStateA());
}
}

class Program
{
static void Main(string[] args)
{
// The client code.
var context = new Context(new ConcreteStateA());
context.Request1();
context.Request2();
// output

// Context: Transition to ConcreteStateA.
// ConcreteStateA handles request1.
// ConcreteStateA wants to change the state of the context.
// Context: Transition to ConcreteStateB.
// ConcreteStateB handles request2.
// ConcreteStateB wants to change the state of the context.
// Context: Transition to ConcreteStateA.
}
}
}