7.行为型模式-状态模式
7.1 基础知识
学习难度:3
使用频率:4
总分:6
定义
状态模式(State Pattern)允许一个对象在其内在状态改变时改变其行为,使得对象看起来像是改变了其类。
说人话
状态模式就像是给对象穿上了不同的外衣,让它在不同的状态下表现出不同的行为。
结构图
实现步骤
- 状态接口:定义状态通用方法,例如进入状态和离开状态的方法,以及可能的行为方法。通常会将上下文类作为参数传入,以便状态对象能够操作上下文。
- 多个具体状态类:实现状态接口,定义具体状态下的行为逻辑。
- 上下文类:维护当前状态对象,并在需要时调用状态对象的方法。定义切换状态的方法,允许外部传入新的状态对象并更新当前状态。
- 客户端:实例化多个具体状态类和上下文类,并将具体状态对象赋值给上下文。通过上下文对象来控制状态的切换和行为的执行。
说明
状态模式可以让代码更加清晰,避免了大量的条件语句,提高了可维护性和扩展性。通过状态模式,可以很容易地新增、删除或修改状态,而不需要修改上下文类中的逻辑。
7.2 模版代码
状态接口和具体状态类
// 状态接口
public interface IState
{
void Handle(Context context);
}
// 具体状态类A
public class ConcreteStateA : IState
{
public void Handle(Context context)
{
Console.WriteLine("上下文处于状态A,执行相关逻辑");
// 这里可以执行与状态A相关的操作
// 也可以根据条件切换到不同的状态
Console.WriteLine("切换至状态B");
context.SetState(new ConcreteStateB());
}
}
// 具体状态类B
public class ConcreteStateB : IState
{
public void Handle(Context context)
{
Console.WriteLine("上下文处于状态B,执行相关逻辑");
// 这里可以执行与状态B相关的操作
// 也可以根据条件切换到不同的状态
Console.WriteLine("切换至状态A");
context.SetState(new ConcreteStateA());
}
}
上下文类
// 上下文类
public class Context
{
private IState currentState;
public Context(IState state)
{
currentState = state;
}
public void SetState(IState state)
{
currentState = state;
}
public void Request()
{
currentState.Handle(this);
}
}
客户端
class Program
{
static void Main(string[] args)
{
//实例化上下文类 初始为状态A
Context context = new Context(new ConcreteStateA());
context.Request(); // 初始状态为ConcreteStateA,执行ConcreteStateA的操作
// 上下文处于状态A,执行相关逻辑
// 切换至状态B
context.Request(); // 切换到ConcreteStateB,执行ConcreteStateB的操作
// 上下文处于状态B,执行相关逻辑
// 切换至状态A
context.Request(); // 再次切换到ConcreteStateA,执行ConcreteStateA的操作
// 上下文处于状态A,执行相关逻辑
// 切换至状态B
}
}
7.3 CSharp实践
实践需求
使用状态模式,模拟员工普通工作,认真工作,和摸鱼状态。
状态接口和具体员工状态类
// 状态接口
public interface IState
{
void DoWork();
}
// 具体状态类:工作中
public class WorkingState : IState
{
public void DoWork()
{
Console.WriteLine("员工正在进行普通工作...");
}
}
// 具体状态类:摸鱼中
public class SlackingState : IState
{
public void DoWork()
{
Console.WriteLine("员工正在摸鱼...");
}
}
// 具体状态类:认真工作中
public class FocusedState : IState
{
public void DoWork()
{
Console.WriteLine("员工正在专心工作...");
}
}
员工类
// 上下文类:员工
public class Employee
{
private IState currentState;
public Employee()
{
// 初始状态为工作中
currentState = new WorkingState();
}
public void SetState(IState state)
{
currentState = state;
}
public void DoWork()
{
currentState.DoWork();
}
}
客户端
class Program
{
static void Main(string[] args)
{
Employee employee = new Employee();
employee.DoWork(); // 初始状态为工作中,执行工作中的操作
employee.SetState(new SlackingState()); // 切换到摸鱼中状态
employee.DoWork(); // 员工处于摸鱼中状态,执行摸鱼的操作
employee.SetState(new FocusedState()); // 切换到认真工作中状态
employee.DoWork(); // 员工处于认真工作中状态,执行专心工作的操作
}
}
7.4 Unity实践
实践需求
使用状态模式,实现按空格随机切换薇恩为默认,移动和攻击状态。
薇恩状态接口和具体薇恩状态类
public interface IVayneState
{
// 进入状态的方法
void EnterState();
// 退出状态的方法
void ExitState();
// 记录状态的方法
void LogState();
}
public class VayneIdleState : IVayneState
{
private Animator animator;
public VayneIdleState(Animator animator)
{
this.animator = animator;
}
public void EnterState()
{
animator.SetBool("IsIdle", true);
}
public void ExitState()
{
animator.SetBool("IsIdle", false);
}
public void LogState()
{
Debug.Log("薇恩正在默认状态");
}
}
public class VayneRunState : IVayneState
{
private Animator animator;
public VayneRunState(Animator animator)
{
this.animator = animator;
}
public void EnterState()
{
animator.SetBool("IsRunning", true); // 播放跑步动画
}
public void ExitState()
{
animator.SetBool("IsRunning", false); // 停止跑步动画
}
public void LogState()
{
// 在跑步状态下执行的行为
Debug.Log("薇恩正在移动");
}
}
public class VayneAttackState : IVayneState
{
private Animator animator;
public VayneAttackState(Animator animator)
{
this.animator = animator;
}
public void EnterState()
{
animator.SetTrigger("Attack"); // 播放攻击动画
}
public void ExitState()
{
// 退出攻击状态的逻辑
}
public void LogState()
{
// 在攻击状态下执行的行为
Debug.Log("薇恩正在攻击...");
}
}
薇恩上下文类
public class VayneContext
{
private IVayneState currentState;
public VayneContext(IVayneState state)
{
currentState = state;
// 进入新状态
currentState.EnterState(); // 调用当前状态的进入状态方法
}
public void ChangeState(IVayneState newState)
{
if (newState == currentState) return;
// 退出当前状态
currentState.ExitState(); // 调用当前状态的退出状态方法
// 切换到新状态
currentState = newState;
// 进入新状态
currentState.EnterState(); // 调用新状态的进入状态方法
}
public void LogState()
{
currentState.LogState(); // 打印当前状态信息
}
}
客户端
public class TestStatePattern : MonoBehaviour
{
private List<IVayneState> vayneStateList = new List<IVayneState>(); // 创建 IVayneState 接口的列表
private VayneContext vayneContext; // 创建 VayneContext 对象
private void Start()
{
GameObject vayneGameObject = Instantiate(Resources.Load<GameObject>("Lesson25_行为型模式_状态模式/Vayne")); // 实例化 Vayne 游戏对象
Animator vayneAnimator = vayneGameObject.GetComponent<Animator>(); // 获取 Vayne 游戏对象上的 Animator 组件
IVayneState idleState = new VayneIdleState(vayneAnimator); // 创建 VayneIdleState 状态对象
IVayneState runState = new VayneRunState(vayneAnimator); // 创建 VayneRunState 状态对象
IVayneState attackState = new VayneAttackState(vayneAnimator); // 创建 VayneAttackState 状态对象
vayneStateList.Add(idleState); // 将 idleState 添加到状态列表
vayneStateList.Add(runState); // 将 runState 添加到状态列表
vayneStateList.Add(attackState); // 将 attackState 添加到状态列表
vayneContext = new VayneContext(idleState); // 创建 VayneContext 上下文对象,初始状态为 idleState
}
private void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
vayneContext.ChangeState(vayneStateList[Random.Range(0, vayneStateList.Count)]); // 在状态列表中随机切换状态
vayneContext.LogState(); // 记录当前状态
}
}
}
运行结果
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com