意图
状态模式的目的是使对象在不同的状态下改变其行为,可以理解为在不同的上下文中,相同的动作导致不同的结果(或导致动作的目的不同)。
使用场合
1.一个对象的行为取决于其运行的状态并且运行时刻根据状态改变自己的行为,如TCP链接对象载Listening、Established盒Closed状态下,对O
pen、Close和Accept执行不同的操作。
2. 一个操作中含有众多分支的条件语句并且这些分支依赖于该对象的状态,如在绘图程序中,鼠标的拖动操作中包含创建或选择图元等操作。而决定采用哪种操作取决于当前操作的状态,即处于图元创建状态,还是处于选择图元状态。
结构
Context(上下文)业务环境:包括一个定义当前会话状态的ConcreteState子类的实例,Context或其客户可以通过改变State指向的具体状态实现状态改变。
State(状态):定义一个封装了Context特定状态相关行为的接口。
ConcreteState subclasses(具体状态子类):每一个类实现一个与Context 的一个状态相关的行为。
初始化时,Context的客户需要实例化可能的状态,并且将初始化状态对象组装到Context中。一旦一个Context配置完毕,其客户不需要再直接与状态对象打交道。
执行时,Context将与状态相关的请求委托给当前ConcreteState对象处理。Context可将自身作为一个参数传递给处理请求的状态对象,使得状态对象在必要时可以访问Context。
Context或ContextState子类及Context的客户均可以决定哪个状态是另外哪一个德后继者,以及是在任何相关条件下进行状态转换。
状态模式的关键是不同状态所具有的行为接口相同。
效果
使用状态模式可以将不同的行为分隔开来,这样来的好处时很容易增加新的状态并实现状态转换而不影响已经存在的状态和Context。
状态模式还避免了操作中庞大的条件分支语句,使代码更容易维护。
代价
使用状态模式的代价是可能产生过多的对象,使动态过程变得复杂。
冷暖空调的控制器
一个空调有3种基本状态,即制冷、制热和不工作。不同的温度条件(即不同的上下文)下空调处于不同的工作状态。如果采用条件语句来实现,那么状态增加时程序将难以维护。
下面采用状态模式来实现空天控制器程序。
定义一个状态接口:
using System.Collections.Generic;
using System.Text;
namespace StatePattern.ex29_3
{
public abstract class AirCondition
{
public AirCondition()
{
}
protected double _targetTemp;
public double TargetTemp
{
get { return _targetTemp; }
set { _targetTemp = value; }
}
//空调启动,输入目标温度和环境温度,输出功率
public abstract double Do(double ttemp, double etemmp);
}
}
定义实现状态接口的具体状态:
制冷状态类
using System.Collections.Generic;
using System.Text;
namespace StatePattern.ex29_3
{
class CoolAirCondition:AirCondition
{
public CoolAirCondition()
{
}
//冷空调,环境温度高于设置温度时工作
public override double Do(double ttemp, double etemp)
{
if (ttemp > etemp)
{
return 0;
}
return (etemp - ttemp) * 200;
}
}
}
制热状态类:
using System.Collections.Generic;
using System.Text;
namespace StatePattern.ex29_3
{
class HotAirCondition : AirCondition
{
public HotAirCondition() { }
public override double Do(double ttemp, double etemmp)
{
if (ttemp < etemmp)
{
return 0;
}
return (ttemp - etemmp)*150;
}
}
}
不工作状态类:
using System.Collections.Generic;
using System.Text;
namespace StatePattern.ex29_3
{
class NoAirCondition : AirCondition
{
//不工作
public override double Do(double ttemp, double etemmp)
{
return 0;
}
}
}
控制器类:
using System.Collections.Generic;
using System.Text;
namespace StatePattern.ex29_3
{
class AirConditionControl
{
private AirCondition hot, cool, non, current;
public AirConditionControl()
{
hot=new HotAirCondition();
cool = new CoolAirCondition();
non = new NoAirCondition();
current = non;
}
public double UpTemp;
public double DownTemp;
public double TargetTemp;
public string CurrentType
{
get { return current.GetType().Name; }
}
public double Do(double evtemp)
{
if (evtemp > UpTemp)
{
current = cool;
}
else if (evtemp < DownTemp)
{
current = hot;
}
else
{
current = non;
}
return current.Do(TargetTemp,evtemp);
}
}
}
执行代码:
{
StatePattern.ex29_3.AirConditionControl ac=new StatePattern.ex29_3.AirConditionControl();
ac.DownTemp = 10;
ac.UpTemp = 30;
ac.TargetTemp = 20;
double e = ac.Do(35);
Console.WriteLine(e);
}
如果需要增加空调的加湿状态,那么只需要增加一个新的状态类。
当然要实现动态增加状态还需要增加一个工厂根据温度动态的提供合适的状态的对象。
相关模式
享元模式:采用享元模式可以实现状态对象的管理。
单件模式:状态对象通常是一个单件。