Unity 设计模式 之 行为型模式 -【状态模式】【观察者模式】【备忘录模式】
目录
Unity 设计模式 之 行为型模式 -【状态模式】【观察者模式】【备忘录模式】
一、简单介绍
设计模式 是指在软件开发中为解决常见问题而总结出的一套 可复用的解决方案。这些模式是经过长期实践证明有效的 编程经验总结,并可以在不同的项目中复用。设计模式并不是代码片段,而是对常见问题的 抽象解决方案,它提供了代码结构和模块间交互的一种设计思路,帮助开发者解决特定的设计问题。
设计模式的特点:
- 通用性:设计模式针对的是软件开发中常见的设计问题,适用于各种软件工程项目。
- 可复用性:设计模式可以在不同项目和环境下被重复使用,提高代码的可维护性和扩展性。
- 可扩展性:设计模式有助于让代码结构更加灵活,易于扩展和修改。
- 模块化:通过设计模式,可以减少代码的耦合性,增强模块间的独立性。
- 提高沟通效率:设计模式为开发者提供了一种通用的设计语言,使得团队成员能够快速理解并讨论设计方案。
二、状态模式(State Pattern)
状态模式(State Pattern) 是一种行为型设计模式,它允许一个对象在其内部状态发生改变时改变其行为。状态模式将与状态相关的行为封装在独立的状态类中,系统在运行时根据状态的变化来切换不同的行为。
通过状态模式,状态转换和行为执行得到了很好的分离,符合面向对象设计的单一职责原则,即每个类只负责一项具体的职责。
状态模式的结构
- 上下文类(Context Class):维护当前状态的引用,负责在运行时根据状态的变化调用不同的状态类的行为。
- 状态接口(State Interface):定义状态类的共同行为,这通常是一个抽象类或接口。
- 具体状态类(Concrete State Class):实现状态接口,提供每个状态下具体的行为。
1、什么时候使用状态模式
-
对象的行为依赖于状态变化时,并且行为会随着状态的不同而发生变化。
-
对象的状态变化频繁,而且状态之间的切换逻辑复杂,状态模式可以很好地管理这些状态。
-
状态转换具有规律性,每个状态都有固定的行为模式或规则,状态模式可以简化这种逻辑。
-
需要避免使用大量条件判断来实现不同状态下的行为时,状态模式是一个更优雅的解决方案。
2、使用状态模式的好处
-
简化条件判断逻辑:通过将状态转换逻辑封装到各个具体状态类中,状态模式避免了大量的
if-else
或switch
语句,代码更清晰。 -
增强系统的扩展性:状态模式将状态相关的行为封装到独立的类中,因此添加新的状态或修改现有状态的行为不会影响其他代码,符合开闭原则。
-
使状态行为与上下文解耦:上下文类仅负责状态的切换,而具体的行为由状态类来实现,保持了上下文类的简洁。
-
提高代码可维护性:状态类各自独立,便于测试、调试和维护。
3、使用状态模式时的注意事项
-
状态类的数量增加:状态模式的一个潜在问题是状态类的数量可能会随着状态的增多而增加,导致类过多。此时需要评估是否有必要使用状态模式,还是可以通过其他方式优化。
-
上下文和状态类的依赖:虽然状态模式将状态行为独立出来,但状态类与上下文之间的相互引用可能导致依赖复杂性,需要控制好状态类的职责。
-
状态转换规则复杂时:如果状态之间的转换规则非常复杂,可能需要将转换逻辑从具体状态类中抽离,避免具体状态类中的代码变得过于庞大。
三、在 Unity 中使用 状态模式
在 Unity 中,状态模式可以很好地用于角色的状态管理,例如角色的运动状态、攻击状态、死亡状态等。我们可以通过状态模式将这些行为封装在不同的状态类中,使得角色能够根据当前状态动态切换行为。
下面我们使用状态模式,实现一个角色可以在站立、行走、奔跑和跳跃状态之间切换的示例,基于 Unity 的 3D 环境。
参考类图如下:
1、定义状态接口
我们首先定义一个接口 ICharacterState
,每个具体的状态类都需要实现该接口。
public interface ICharacterState
{
void HandleInput(Character character);
void UpdateState(Character character);
}
2、具体状态类
根据不同的角色状态(站立、行走、奔跑、跳跃),我们为每个状态创建一个具体的类。每个状态类都实现了 ICharacterState
接口。
using UnityEngine;
// 站立状态类
public class StandState : ICharacterState
{
public void HandleInput(Character character)
{
if (Input.GetKeyDown(KeyCode.W))
{
character.SetState(new WalkState());
}
}
public void UpdateState(Character character)
{
Debug.Log("角色正在站立");
}
}
// 行走状态类
public class WalkState : ICharacterState
{
public void HandleInput(Character character)
{
if (Input.GetKeyDown(KeyCode.R))
{
character.SetState(new RunState());
}
else if (Input.GetKeyDown(KeyCode.Space))
{
character.SetState(new JumpState());
}
}
public void UpdateState(Character character)
{
character.transform.Translate(Vector3.forward * 2f * Time.deltaTime);
Debug.Log("角色正在行走");
}
}
// 奔跑状态类
public class RunState : ICharacterState
{
public void HandleInput(Character character)
{
if (Input.GetKeyDown(KeyCode.Space))
{
character.SetState(new JumpState());
}
}
public void UpdateState(Character character)
{
character.transform.Translate(Vector3.forward * 5f * Time.deltaTime);
Debug.Log("角色正在奔跑");
}
}
// 跳跃状态类
public class JumpState : ICharacterState
{
public void HandleInput(Character character)
{
// 空中不允许其他输入
}
public void UpdateState(Character character)
{
character.transform.Translate(Vector3.up * 5f * Time.deltaTime);
Debug.Log("角色正在跳跃");
// 跳跃结束后返回站立状态
character.SetState(new StandState());
}
}
3、上下文类
接下来定义上下文类 Character
,它维护当前的状态,并通过 SetState()
方法进行状