状态模式
当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类
abstractclass State
{
public abstract void Handler(Context context);
};
class ConcretStateA :State
{
public override void Handler(Context context)
{
context.State = new ConcretStateB();
}
};
class ConcretState :State
{
public override void Handler(Context context)
{
context.State = new ConcretStateA();
}
};
class Context
{
private State state;
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.Handler(this); //对请求做处理并设置下一个状态
}
};
void main()
{
Context c = new Context(new ConcretStateA());
c.Request(); //不断的请求同时更改状态
c.Request();
c.Request();
c.Request();
}
状态模式主要解决的是当前控制一个对象状态转换的条件表达式过于复杂时的情况,把状态的判断逻辑移到表示不同状态d一些列类当中,可以把复杂的判断简化。
状态模式的好处:
将与特定状态相关的行为局部化,并且将不同状态的行分割开来
将于特定状态相关的行为都放入一个对象中,由于所有与状态相关的代码都存在于某个ConcretState中,所以通过定义新的子类可以很容易的增加新的状态和转换
说白了就是消除庞大的条件分支语句,把状态逻辑转移分布到State的子类间,来减少相互间的依赖
何时使用呢?
当一个对象的行为取决于他的状态,并且必须在运行时候根据状态改变它的行为的时候,就考虑使用状态模式
下面就给出一个实例,是根据工作时间的改变导致员工精神状态改变的例子
abstractclass State
{
public abstract void WriteProgram(Work w);
};
//上午的工作状态类
class MorningState():State
{
public override void WriteProgram(Work w)
{
if (w.Hour < 12)
{
Console.WriteLine("当前时间:{0} 精神百倍",w.Hour);
}
else //超过12点则是中午状态
{
w.SetState(new NoonState());
w.WriteProgram();
}
}
}
//中午状态类
class NoonState() :State
{
public override void WriteProgram(Work w)
{
if (w.Hour < 13)
{
Console.WriteLine("当前时间:{0} 饿了", w.Hour);
}
else //超过13点则是下午状态
{
w.SetState(new AfternoonState());
w.WriteProgram();
}
}
}
//下午状态
classAfternoonState:State
{
//...
};
//晚间
class EveningState: State
{
public override void WriteProgram(Work w)
{
if (w.taskfinished) //工作完成
{
w.SetState(new RestState);
w.WriteProgram();
}
else
{
if (w.Hour < 21)
Console.WriteLine("累趴");
else
{
w.SetState(new SleepingState); //累的睡着了
w.WriteProgram();
}
}
}
};
class Work
{
private State current;
public Work()
{
current = new MorningState();
}
private double hour;
public double Hour
{
get{ return hour; }
set{ hour = value; }
}
private double finish = false;;
public double taskfinis
{
get{ return finish; }
set{ finiah = value; }
}
public void SetState(State s)
{
current= s;
}
public void WriteProgram()
{
current.WriteProgram(this);
}
};
void main(){
Work emergency = new Work();
emergency.Hour = 9;
emergency.WriteProgram();
emergency.Hour = 10;
emergency.WriteProgram();
//...
}
除了以上的使用方式之外,一些情况下对象之前的状态需要共享,这时候让我们看看如何处理
共享状态
在有些情况下,多个环境对象可能需要共享同一个状态,如果希望在系统中实现多个环境对象共享一个或多个状态对象,那么需要将这些对象定义为环境类的静态成员对象
以下据一个例子:
某系统要求两个开关对象要么都处于开的状态,要么都处于关的状态,在使用他们的时候必须保持一致。每个开关都可以开或者关,只是可能影响另一个。
实现如下:
//开关类
class Switch
{
//定义3个静态的状态对象
//这就表示此结构体创建的对象将共享状态
private static SwitchState currentState, onState, offState;
private string name;
public Switch(string name)
{
this.name = name;
onState = new OnState();
offState = new OffState();
currentState = onState;
}
public void SetState(SwitchState state)
{
currentState = state;
}
//静态函数,以后谁要设置状态就通过此函数返回的静态对象设置
public static SwitchState GetState(string type)
{
if(type.Equal("on"))
return onState;
return offState;
}
public void on()
{
Console.WriteLine(name);
//通过当前状态调用打开函数
currentState.On(this);
}
public void off()
{
Console.WriteLine(name);
//同上
currentState.Off(this);
}
}
//状态类
abstract class SwitchState
{
//在某种状态下执行某种操作
public abstract void On(Switch s);
public abstract void Off(Switch s);
}
//开状态
class OnState: SwitchState
{
//开的时候还执行开就提醒一下
public override void On(Switch s)
{
Console.WriteLine("Already On!");
}
public override void Off(Switch s)
{
Console.WriteLine("Close!");
//通过静态函数获得该类型中的静态对象
s.SetState(Switch.GetState("off"));
}
}
//关状态
class OffState: SwitchState
{
public override void Off(Switch s)
{
Console.WriteLine("Already Off!");
}
public override void On(Switch s)
{
Console.WriteLine("Open!");
//通过静态函数获得该类型中的静态对象
s.SetState(Switch.GetState("on"));
}
}
//客户端
void main()
{
Switch s1, s2;
s1 = new Switch("开关1");
s2 = new Switch("开关2");
s1.Off();
s2.Off();
}
输出结果为:
Close!
Already Off!
状态模式也有其不好的地方,比如会增加系统中类的个数,导致系统运行开销增加
比如结构复杂,稍不注意就混乱了
比如对开闭原则的支持并不好,增加新的状态需要修改上一个状态的内容,否则无法从上一个状态转移到新状态