【设计模式&C#】状态模式(用于解决解耦多种状态之间的交互)

一种行为设计模式。

特点是用类的方式去管理状态。
优点:

  1. 对每个状态进行了封装,提高了代码的可维护性;
  2. 减少了条件判断语句的使用,降低维护成本;
  3. 易于扩展,每次新增状态都无需大规模修改其他类,符合开闭原则;

缺点:

  1. 会导致类的增加,每个状态都会是一个单独的类;
  2. 增加了性能的开销,状态的实例化会导致性能消耗增加。

用途:

  1. 设计游戏中人物的状态
  2. 设计网络连接时的状态
  3. 设计订单的状态
    主要组成部分:

状态的接口:它定义了每个状态的实现规则。

每个状态的具体实现类:定义了状态的具体的实现逻辑和切换逻辑。

上下文(或者叫控制器):维护一个具体状态的引用,通常是指调用状态对象。

实例:

cs 复制代码
//状态的接口
using UnityEngine;

/// <summary>
/// 每个场景的状态接口类
/// </summary>
public abstract class ISceneState
{   
    private string mSceneName;//场景名称
    protected SceneStateController mController;//场景状态控制器

    public ISceneState(string sceneName, SceneStateController controller)
    {
        mSceneName = sceneName;
        mController = controller;
    }

    public string SceneName
    {
        get { return mSceneName; }
    }

    /// <summary>
    /// 状态开始时调用
    /// </summary>
    public virtual void StateStart() { }

    /// <summary>
    /// 状态结束时调用
    /// </summary>
    public virtual void StateEnd() { }

    /// <summary>
    /// 状态更新时调用
    /// </summary>
    public virtual void StateUpdate() { }
}
cs 复制代码
//状态的实现类
using UnityEngine;
using UnityEngine.UI;

public class StartState: ISceneState
{
    public StartState(SceneStateController controller) :base("01StartScene", controller)
    {

    }

    private Image mLOGO;
    private float mSmoothingTime = 1f;//LOGO过渡时间
    private float mWaitTime = 2f;//进入MainMenue前等待时间

    public override void StateStart()
    {
        mLOGO = GameObject.Find("Canvas/LOGO").GetComponent<Image>();

        mLOGO.color = Color.black;
    }

    public override void StateUpdate()
    {
        //LOGO图片的缓冲过渡
        mLOGO.color = Color.Lerp(mLOGO.color, Color.white, mSmoothingTime * Time.deltaTime);

        //等待时间
        mWaitTime -= Time.deltaTime;

        //LOGO图片的缓冲过渡
        if(mWaitTime <= 0)
        {
            mController.SetState(new MainMenuState(mController));
        }
    }
}
cs 复制代码
//状态的实现类
using UnityEngine;
using UnityEngine.UI;

public class MainMenuState: ISceneState
{
    public MainMenuState(SceneStateController controller): base("02MainMenuScene", controller)
    {
        
    }

    public override void StateStart()
    {
        GameObject.Find("Canvas/StartButton").GetComponent<Button>().onClick.AddListener(StartGameButtonOnClick);
    }

    public void StartGameButtonOnClick()
    {
        mController.SetState(new BattleState(mController));
    }
}
cs 复制代码
//状态的实现类
public class BattleState: ISceneState
{
    public BattleState(SceneStateController controller): base("03BattleScene", controller)
    {

    }

    public override void StateStart()
    {
        GameFacade.Instance.Init();
    }

    public override void StateEnd()
    {
        GameFacade.Instance.Release();
    }

    public override void StateUpdate()
    {   
        if(GameFacade.Instance.isGameOver)
        {
            mController.SetState(new MainMenuState(mController));
        }

        GameFacade.Instance.Update();
    }
}
cs 复制代码
//上下文(或者叫控制器):
using UnityEngine;
using UnityEngine.SceneManagement;

public class SceneStateController
{
    private ISceneState mState;//当前场景状态
    private AsyncOperation mAO;//异步加载场景
    private bool mIsRunStart = false;//表示场景是否已经正在运行中

    /// <summary>
    /// 设置场景状态
    /// </summary>
    /// <param name="state">状态</param>
    /// <param name="isLoadScene">是否加载场景</param>
    public void SetState(ISceneState state, bool isLoadScene = true)
    {   
        //退出状态时的处理
        if(mState != null)
        {
            mState.StateEnd();
        }

        //设置新状态
        mState = state;

        //加载场景
        if(isLoadScene)
        {
            mAO = SceneManager.LoadSceneAsync(mState.SceneName);
            mIsRunStart = false;
        }
        else
        {
            mState.StateStart();
            mIsRunStart = true;
        }
    }

    /// <summary>
    /// 更新场景状态
    /// </summary>
    public void StateUpdate()
    {
        if (mAO != null && mAO.isDone == false) return;

        if(mIsRunStart == false && mAO != null && mAO.isDone == true)
        {
            mState.StateStart();
            mIsRunStart = true;
        }

        if(mIsRunStart && mState != null)
        {
            mState.StateUpdate();
        }
    }
}
相关推荐
牛哇网络工作室4 小时前
UnityHDRP写实数字人全流程基础5—语音输入和语音识别
android·unity·c#·游戏引擎·aigc·语音识别·xcode
用户938515635076 小时前
工厂模式与 Nest.js 核心思想 —— 从蜜雪冰城到企业级架构
后端·设计模式·nestjs
烬羽10 小时前
从 nest new 到 Hello World:一个最小 NestJS 项目,讲透工厂 + 装饰器 + 模块化
设计模式·node.js·nestjs
Java&Develop14 小时前
QuantDinger 宝塔 Linux 部署完整指南
linux·运维·状态模式
zlinear数据采集卡15 小时前
数据采集卡从入门到精通(9):分辨率与精度——16位卡不等于1/65536的精度
开发语言·数据库·fpga开发·开源·c#
星恒随风17 小时前
C++ 红黑树封装(二):迭代器、const_iterator 与 operator[] 完整实现 mymap 和 myset
开发语言·c++·状态模式
深澈Vincel17 小时前
我用 C# + WebView2 做了一个针对“流氓软件”的“一键清理工具“:架构实践与踩坑记录
c#
zlinear数据采集卡18 小时前
数据采集卡从入门到精通(7):流水线型ADC——级级接力,高速与高精的平衡术
开发语言·arm开发·嵌入式硬件·fpga开发·c#
sugar__salt19 小时前
在浏览器里跑 DeepSeek-R1:用 WebGPU 把大模型搬进前端
前端·javascript·状态模式
火云牌神19 小时前
异常与统一封装架构:规范统一返回值、全局异常与参数校验
架构·状态模式·ai编程·vibecoding