定义
允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。
状态模式用于解决系统中复杂对象的状态转换以及不同状态下行为的封装问题。当系统中的某个对象存在多个状态,这些状态之间可以进行转换,而且对象在不同状态下行为不相同时可以使用状态模式。状态模式将一个对象的状态从该对象中分离出来,封装到专门的状态类中,使得对象状态可以灵活变化。对于客户端而言,无须关心对象状态的转换以及对象所处的当前状态,无论对于何种状态的对象,客户端都可以一致处理。
举例
水的状态可以有多种,如:平常的流动状态,形成冰的固体状态,水蒸气的气态
结构
实现
//抽象状态类,定义一个接口以封装与Context的一个特定状态相关的行为。
abstract class State
{
public abstract void Handle(Context context);
}
//具体状态,每一个子类实现一个与Context的一个状态相关的行为。
class ConcreteStateA : State
{
public override void Handle(Context context)
{
context.State = new ConcreteStateB();
}
}
class ConcreteStateB: State
{
public override void Handle(Context context)
{
context.State = new ConcreteStateA();
}
}
//维护一个ConcreteState子类的实例,这个实例定义当前的状态。
class Context
{
private State state;
//定义Context初始状态
public Context(State state)
{
this.state = state;
}
//可读写的状态属性,用于读取当前状态和设置新状态
public State State
{
get { return state; }
set {
state = value;
Console.WriteLine("当前状态:" + state.GetType().Name);
}
}
//对请求做处理,并设置下一状态
public void Request()
{
state.Handle(this);
}
}
class Program
{
static void Main(string[] args)
{
//设置Context的初始状态为 ConcreteStateA
Context c = new Context(new ConcreteStateA());
//不断请求更新状态
c.Request();
c.Request();
c.Request();
c.Request();
}
}
优点
- (1)状态模式封装了状态的转换规则,在状态模式中可以将状态的转换代码封装在环境类或者具体状态类中,可以对状态转换代码进行集中管理,而不是分散在一个个业务方法中。
- (2)状态模式将所有与某个状态有关的行为放,到一个类中,只需要注入一个不同的状态对象即可使环境对象拥有不同的行为。
- (3)状态模式允许状态转换逻辑与状态对象合成一体,而不是提供一个巨大的条件语句块,状态模式可以避免使用庞大的条件语句将业务方法和状态转换代码交织在一起。
- (4)状态模式可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数。
缺点
- (1)状态模式会增加系统中类和对象的个数,导致系统运行开销增大。
- (2)其结构与实现都较为复杂,如果使用不当将导致程序结构和代码混乱,增加系统设计的难度。
- (3)状态模式对开闭原则的支持并不太好,增加新的状态类需要修改负责状态转换的源代码,否则无法转换到新增状态,而且修改某个状态类的行为也需要修改对应类的源代码。
适用环境
- (1)对象的行为依赖于它的状态(例如某些属性值),状态的改变将导致行为的变化。
- (2)在代码中包含大量与对象状态有关的条件语句,这些条件语句的出现会导致代码的可维护性和灵活性变差,不能方便地增加和删除状态,并且导致客户类与类库之间的耦合增强。