今天写个状态机,吧。
先假设我们的角色只有两个状态:攻击状态和受击状态。
一般情况下,我们的代码可能是这样的:
public enum State
{
Attack,
BeHit,
}
public class Player
{
State state;
public Player()
{
state = State.Attack;
}
public State GetPlayerState()
{
return state;
}
public void SetPlayerState(State state)
{
this.state = state;
}
}
class Program
{
static void Main(string[] args)
{
Player player = new Player();
if(player.GetPlayerState() == State.Attack)
{
//干Attack时的事儿
//....
//当受击时,切换到BeHit状态
player.SetPlayerState(State.BeHit);
}
else if(player.GetPlayerState() == State.BeHit)
{
//干BeHit时的事儿
//....
//当受击结束,切换到Attack状态
player.SetPlayerState(State.Attack);
}
}
}
简单明了,客户根据角色当前的状态,当满足对应条件时,切换到新的状态。
好了,现在让我们为角色添加一个新状态:眩晕状态。
我们先在枚举中添写,然后。。。就是在最后一个else if后面添加一个else if,写上眩晕状态时需要做的事儿。
这还不是最恐怖的,最口怕的是,还要在之前的两个状态里,添加对眩晕状态的条件判断。
当添加的状态足够多。。。太容易出错了。
这是因为客户和每个状态的具体实现耦合在了一起。
下面我们看一个新的结构:
public interface PlayerState
{
void Attack();
void Behit();
}
public class AttackState : PlayerState
{
Player player;
public AttackState(Player player)
{
this.player = player;
}
public void Attack()
{
//攻击
}
public void Behit()
{
player.SetState(player.GetBeHitState());
}
}
public class BeHitState : PlayerState
{
Player player;
public BeHitState(Player player)
{
this.player = player;
}
public void Attack()
{
player.SetState(player.GetAttackState());
}
public void Behit()
{
//受击
}
}
public class Player
{
PlayerState attackState;
PlayerState beHitState;
PlayerState state;
public Player()
{
attackState = new AttackState(this);
beHitState = new BeHitState(this);
state = attackState;
}
public void Attack()
{
state.Attack();
}
public void BeHit()
{
state.Behit();
}
public PlayerState GetAttackState()
{
return attackState;
}
public PlayerState GetBeHitState()
{
return beHitState;
}
public void SetState(PlayerState state)
{
this.state = state;
}
}
这个结构一个很明显的特点:篇幅长。
一本正经的胡说八道。。
最明显的一个特点:把每个状态封装进一个类!
这种结构,客户不知道也不关心状态机的具体行为,他甚至不知道状态机当前处于什么状态!这样,客户只拥有一个状态实例,他只需要在执行每个行为时,调用状态实力的对应方法就好了,至于状态的细节(当前状态做什么事儿,状态的切换),交给每个状态自己做就好了,客户与状态的实现解耦。
现在,当我们再想要添加一个新的状态时,就可以肆无忌惮,这个状态做好自己该做的就好了,不担心会影响到别的状态,也不会被别的状态影响!
一句话总结状态模式:把每一个状态封装成独立的类。