【Unity 框架】QFramework v1.0 使用指南 架构篇:03. 引入 Command | Unity 游戏框架 | Unity 游戏开发 | Unity 独立游戏

03. 引入 Command

我们回顾一下目前的代码,如下;

using UnityEngine;
using UnityEngine.UI;

namespace QFramework.Example
{
    
    // 1. 定义一个 Model 对象
    public class CounterAppModel : AbstractModel
    {
        public int Count;
        
        protected override void OnInit()
        {
            Count = 0;
        }
    }


    // 2.定义一个架构(提供 MVC、分层、模块管理等)
    public class CounterApp : Architecture<CounterApp>
    {
        protected override void Init()
        {
            // 注册 Model
            this.RegisterModel(new CounterAppModel());
        }
    }

    // Controller
    public class CounterAppController : MonoBehaviour , IController /* 3.实现 IController 接口 */
    {
        // View
        private Button mBtnAdd;
        private Button mBtnSub;
        private Text mCountText;
        
        // 4. Model
        private CounterAppModel mModel;

        void Start()
        {
            // 5. 获取模型
            mModel = this.GetModel<CounterAppModel>();
            
            // View 组件获取
            mBtnAdd = transform.Find("BtnAdd").GetComponent<Button>();
            mBtnSub = transform.Find("BtnSub").GetComponent<Button>();
            mCountText = transform.Find("CountText").GetComponent<Text>();
            
            
            // 监听输入
            mBtnAdd.onClick.AddListener(() =>
            {
                // 6. 交互逻辑
                mModel.Count++;
                // 表现逻辑
                UpdateView();        
            });
            
            mBtnSub.onClick.AddListener(() =>
            {
                // 7. 交互逻辑
                mModel.Count--;
                // 表现逻辑
                UpdateView();
            });
            
            UpdateView();
        }
        
        void UpdateView()
        {
            mCountText.text = mModel.Count.ToString();
        }

        // 3.
        public IArchitecture GetArchitecture()
        {
            return CounterApp.Interface;
        }

        private void OnDestroy()
        {
            // 8. 将 Model 设置为空
            mModel = null;
        }
    }
}

现在,数据共享的问题通过 引入 Model 解决了。

这里再次强调一下,需要共享的数据放 Model 里,不需要共享的,能不放就不放。

虽然引入了 Model,但是这套代码随着项目规模的发展还是有很多的问题。

其中最严重也最常见的就是 Controller 会越来越臃肿。

我们简单分析一下为什么 Controller 会越来越臃肿,我们先看下监听用户输入部分的代码,如下:

// 监听输入
mBtnAdd.onClick.AddListener(() =>
{
    // 交互逻辑
    mModel.Count++;
    // 表现逻辑
    UpdateView();        
});
            
mBtnSub.onClick.AddListener(() =>
{
    // 交互逻辑
    mModel.Count--;
    // 表现逻辑
    UpdateView();
});

在处理用户输入的代码中,笔者写了注释,交互逻辑 和 表现逻辑。

什么是交互逻辑 和 表现逻辑?

非常简单。

交互逻辑,就是从用户输入开始到数据变更的逻辑

顺序是 View->Controller->Model

表现逻辑,就是数据变更到在界面显示的逻辑

顺序是 Model->Controller->View

如下图所示:

image.png

虽然交互逻辑和表现逻辑理解起来简单,但是它们非常重要,因为 QFramework 接下来的概念都是围绕这两个概念展开的。

View、Model 以及 Controller 的交互逻辑和表现逻辑形成了一个闭环。构成了完整的 MVC 闭环。

而 Controller 本身之所以臃肿,是因为,它负责了两种职责,即改变 Model 数据 的交互逻辑,以及 Model 数据变更之后更新到界面的表现逻辑。

而在一个有一定规模的项目中,表现逻辑和交互逻辑非常多。而一个 Controller 很容易就做到上千行代码。

而大部分的 MVC 方案,解决 Controller 臃肿用的是引入 Command 的方式,即引入命令模式,通过命令来分担 Controller 的交互逻辑的职责。

QFramework 也是使用了同样的方式解决 Controller 臃肿的问题。

我们将代码改成如下:

using UnityEngine;
using UnityEngine.UI;

namespace QFramework.Example
{
    
    // 1. 定义一个 Model 对象
    public class CounterAppModel : AbstractModel
    {
        public int Count;
        
        protected override void OnInit()
        {
            Count = 0;
        }
    }


    // 2.定义一个架构(提供 MVC、分层、模块管理等)
    public class CounterApp : Architecture<CounterApp>
    {
        protected override void Init()
        {
            // 注册 Model
            this.RegisterModel(new CounterAppModel());
        }
    }
    
    // 引入 Command
    public class IncreaseCountCommand : AbstractCommand // ++
    {
        protected override void OnExecute()
        {
            this.GetModel<CounterAppModel>().Count++;
        }
    }
    
    public class DecreaseCountCommand : AbstractCommand // ++
    {
        protected override void OnExecute()
        {
            this.GetModel<CounterAppModel>().Count--;
        }
    }

    // Controller
    public class CounterAppController : MonoBehaviour , IController /* 3.实现 IController 接口 */
    {
        // View
        private Button mBtnAdd;
        private Button mBtnSub;
        private Text mCountText;
        
        // 4. Model
        private CounterAppModel mModel;

        void Start()
        {
            // 5. 获取模型
            mModel = this.GetModel<CounterAppModel>();
            
            // View 组件获取
            mBtnAdd = transform.Find("BtnAdd").GetComponent<Button>();
            mBtnSub = transform.Find("BtnSub").GetComponent<Button>();
            mCountText = transform.Find("CountText").GetComponent<Text>();
            
            
            // 监听输入
            mBtnAdd.onClick.AddListener(() =>
            {
                // 交互逻辑
                this.SendCommand<IncreaseCountCommand>();
                // 表现逻辑
                UpdateView();        
            });
            
            mBtnSub.onClick.AddListener(() =>
            {
                // 交互逻辑
                this.SendCommand<DecreaseCountCommand>();
                // 表现逻辑
                UpdateView();
            });
            
            UpdateView();
        }
        
        void UpdateView()
        {
            mCountText.text = mModel.Count.ToString();
        }

        // 3.
        public IArchitecture GetArchitecture()
        {
            return CounterApp.Interface;
        }

        private void OnDestroy()
        {
            // 8. 将 Model 设置为空
            mModel = null;
        }
    }
}

代码很简单,我们用流程图表示如下:

image.png

运行 Unity,结果如下:

282fcc3c-96fa-46e1-b4c6-7f4528b04271.gif

没有变化,运行正确。

大家可能会问,一个简单的数据加减操作,至于创建一个 Command 对象来承担么?看不出来好处呀,反而代码更多了。

如果整个项目只有一个简单的数据加减操作,那使用 Command 有点多此一举,但是一般的项目的交互逻辑,是非常复杂的,代码量也非常多,整个时候使用 Command 词汇发挥作用。

具体发挥什么作用,使用 Command 可以带来很多便利,比如:

  • Command 可以复用,Command 也可以调用 Command
  • Command 可以比较方便实现撤销功能,如果 App 或者 游戏需要的话
  • 如果遵循一定规范,可以实现使用 Command 跑自动化测试。
  • Command 可以定制 Command 队列,也可以让 Command 按照特定的方式执行
  • 一个 Command 也可以封装成一个 Http 或者 TCP 里的一次数据请求
  • Command 可以实现 Command 中间件模式
  • 等等

OK,通过引入 Command,帮助分担了 Controller 的交互逻辑。使得 Controller 成为一个薄薄的一层,在需要修改 Model 的时候,Controller 只要调用一句简单的 Command 即可。

Command 最明显的好处就是:

  • 就算代码再乱,也只是在一个 Command 对象里乱,而不会影响其他的对象。
  • 讲方法封装成命令对象,可以实现对命令对象的组织、排序、延时等操作。

更多好处会随着大家的实践慢慢体会到。

当前的 MVC 流程如下:

这篇内容就这些。

更多内容

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

凉鞋的笔记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值