状态模式主要解决的是当控制一个对象状态转化的条件表达式过于复杂时的情况。把状态的判断逻辑转移到表示不太状态的一系列类当中,可以把复杂的判断逻辑简化。
状态模式UML图
State类,抽象状态类,定义一个接口以封装与Context的一个特定状态相关的行为
abstract class State
{
public abstract void Handle(Context context);//使用context去实现行为,保持了状态的一致性
}
ConcreteState类,具体类,每一个子类实现一个与Context的一个状态相关的行为。
class ConcreteStateA:State
{
public override void Handle(Context context)//状态相关的行为
{
context.State=new ConcreteStateB();//设置A状态的下一状态是B状态
}
}
class ConcreteStateB:State
{
public override void Handle(Context context)
{
context.State=new ConcreteStateA();
}
}
Context上下文类,维护一个ConcreteState子类的实例,这个实例定义当前的状态
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.Handle(this);
}
}
客户端代码
static void Main(string[] args)
{
Context c=new Context(new ConcreteStateA());//初始状态设置为A
c.Request();
c.Request();
c.Request();
c.Request();//不断的请求,同时更改状态
Console.Read();
}
进一步了解
状态模式的本质:
- 根据状态来分离和选择行为
- 状态模式是由状态驱动,由上下文负责
状态模式的优点:
- 将与特定状态相关的行为局部化,并且将不同状态的行为分割开来
- 消除庞大的条件分支语句,把各种状态转移逻辑分布到State的子类之间,减少了相互间的依赖
- 保持了状态的一致性(显示化进行状态转换:为不同的状态引入独立的对象,使得状态的转换变得更加明确。而且状态对象可以保证上下文不会发生内部状态不一致的状况,因为上下文只有一个变量来记录状态对象,只需要为一个状态变量赋值就可以了。)
状态模式的缺点:
- 逻辑分散化,状态逻辑分布到了很多的State的子类中,很难看到整个状态逻辑图,这也带来了代码的维护问题。
实例操作
1、采用状态模式实现工作流中的请假流程(代码+UML类图)
某人提出请假申请,先由项目经理审批,如果项目经理不同意,审批就直接结束
如项目经理同意,再看是否超过3天,如果三天以内,审批直接结束
否则,交给部门经理,部门经理审核后,无论是否同意,审批直接结束
###UML图
State状态抽象类
public abstract class State {
public abstract void Yijian(PersonContext p);//封装特定状态的相关行为
protected abstract void setFlag(boolean flag);
}
项目经理状态类
public class Projectmanager extends State {
private boolean flag;
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
//项目经理给出意见
this.flag = flag;
}
@Override
public void Yijian(PersonContext p) {
//根据项目经理的意见,去实现项目经理状态下的行为与状态转移
if(flag) {
if(p.getDay()<=3) {
p.setFlag(true);
System.out.println("申请"+p.getDay()+"天假期,项目经理批准。开始休假。");
}else {
System.out.println("申请"+p.getDay()+"天假期,项目经理批准。等待部门经理审批。");
p.setState(new DepartmentManager());//状态转移
}
}else {
p.setFlag(false);
System.out.println("申请"+p.getDay()+"天假期,项目经理不批准。");
}
}
}
部门经理类
public class DepartmentManager extends State {
private boolean flag;
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
//部门经理给出意见
this.flag = flag;
}
@Override
public void Yijian(PersonContext p) {
//根据部门经理的意见,去实现部门经理状态下的行为与状态转移
if(flag) {
if(p.getDay()<=7) {
p.setFlag(true);
System.out.println("申请"+p.getDay()+"天假期,项目经理、部门经理批准。开始休假。");
}else {
System.out.println("申请"+p.getDay()+"天假期,项目经理、部门经理批准。等待人事经理审批。");
p.setState(new HRManager());//状态转移
}
}else {
p.setFlag(false);
System.out.println("申请"+p.getDay()+"天假期,部门经理不批准。");
}
}
}
人事部门类
public class HRManager extends State {
private boolean flag;
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
@Override
public void Yijian(PersonContext p) {
if(flag) {
p.setFlag(true);
System.out.println("申请"+p.getDay()+"天假期,项目经理、部门经理、人事经理批准。");
}else {
p.setFlag(false);
System.out.println("申请"+p.getDay()+"天假期,人事经理不批准。");
}
}
}
客户端类及运行效果