(20)行为型模式——状态
程序员文章站
2022-06-14 23:30:59
...
行为型模式——状态(State)
问题背景
当希望对象的行为会随着状态改变而改变时,考虑使用状态。想想LoL,玩家可以让他们操控的英雄移动、攻击、使用技能等,而英雄在一局游戏里会有很多种状态,比如正常、眩晕、沉默、死亡…英雄在不同状态下对不同指令的响应方式可能会有不同。正常状态下英雄会响应任何指令,而眩晕状态下则只响应特定的技能(净化、水银、五秒真男人…),沉默状态下不会使用技能,死亡状态下只能看装备…
按照套路,这种情况肯定是不能直接用if或者switch的,因为状态的种类可能会变多(@睡眠@缴械),为了应对变化,就需要把状态这个概念抽象出来。
解决方案
本来,我们可以在英雄类里处理各种指令的响应逻辑。但上面也说了,当状态种类变多时,就得修改英雄类,破坏了开闭原则。于是,我们把这部分逻辑从英雄类中剥离出来,交给一个“状态”类来实现。提取出一个状态接口IState,包含Move,Attack和UseSkill方法,英雄类持有一个对IState的引用,当英雄收到指令时,就把指令转发给IState做处理。使用状态后,程序结构是这样的:
效果
- 将不同状态的逻辑从对象中剥离,增强了系统的可扩展性。
- 使对象能显示地转换状态,增强了系统的可理解性。
缺陷
很多时候,状态对象本身会改变上下文的状态,因此状态对象需要持有对上下文的引用。为了在状态对象中直接转换状态,各个具体对象之间必须了解彼此,无法做到完全解耦,当加入新状态时,总会有地方需要修改。
相关模式
- 享元:状态对象的一些属性可以实现共享。
- 单例:无状态的状态对象可以实现为单例。
实现
using System;
namespace State
{
class Client
{
public interface IState
{
void Move();
void Attack();
void UseSkill();
void ChangeState();
}
public class Champion
{
public int Count { get; set; }
public IState State { get; set; }
public void Move()
{
State.Move();
}
public void Attack()
{
State.Attack();
}
public void UseSkill()
{
State.UseSkill();
}
public void ChangeState()
{
if (State == null)
{
State = new Normal(this);
} else
{
State.ChangeState();
}
}
}
public class Normal : IState
{
private Champion champion;
public Normal(Champion champion)
{
this.champion = champion;
}
public void Move()
{
Console.WriteLine("状态正常,移动");
}
public void Attack()
{
Console.WriteLine("状态正常,攻击");
}
public void UseSkill()
{
Console.WriteLine("状态正常,使用技能");
}
public void ChangeState()
{
switch (champion.Count++ % 3)
{
case 0:
Console.WriteLine("你被眩晕");
champion.State = new Stun(champion);
break;
case 1:
Console.WriteLine("你被沉默");
champion.State = new Silence(champion);
break;
case 2:
Console.WriteLine("你死了");
champion.State = new Dead(champion);
break;
}
}
}
public class Stun : IState
{
private Champion champion;
public Stun(Champion champion)
{
this.champion = champion;
}
public void Move()
{
Console.WriteLine("眩晕状态,不能移动");
}
public void Attack()
{
Console.WriteLine("眩晕状态,不能攻击");
}
public void UseSkill()
{
Console.WriteLine("眩晕状态,不能使用技能");
}
public void ChangeState()
{
champion.State = new Normal(champion);
champion.State.ChangeState();
}
}
public class Silence : IState
{
private Champion champion;
public Silence(Champion champion)
{
this.champion = champion;
}
public void Move()
{
Console.WriteLine("沉默状态,移动");
}
public void Attack()
{
Console.WriteLine("沉默状态,攻击");
}
public void UseSkill()
{
Console.WriteLine("沉默状态,不能使用技能");
}
public void ChangeState()
{
champion.State = new Normal(champion);
champion.State.ChangeState();
}
}
public class Dead : IState
{
private Champion champion;
public Dead(Champion champion)
{
this.champion = champion;
}
public void Move()
{
Console.WriteLine("你已经死亡,不能移动");
}
public void Attack()
{
Console.WriteLine("你已经死亡,不能攻击");
}
public void UseSkill()
{
Console.WriteLine("你已经死亡,不能使用技能");
}
public void ChangeState()
{
champion.State = new Normal(champion);
champion.State.ChangeState();
}
}
static void Main(string[] args)
{
var champion = new Champion();
champion.ChangeState();
champion.Move();
champion.Attack();
champion.UseSkill();
champion.ChangeState();
champion.Move();
champion.Attack();
champion.UseSkill();
champion.ChangeState();
champion.Move();
champion.Attack();
champion.UseSkill();
champion.ChangeState();
champion.Move();
champion.Attack();
champion.UseSkill();
champion.ChangeState();
champion.Move();
champion.Attack();
champion.UseSkill();
}
}
}
上一篇: 设计模式->行为型模式->状态模式
下一篇: 插件小程序 尝试