SiYangSimpleMvc
一个轻量级、最简、易用的Mvc框架。
零、MVC最简总结
一句话版:
Model 管数据,View 管显示,Controller 管交互与流程。
精确定义:
-
Model(模型) :
负责业务规则与数据状态,不关心界面如何显示。
-
View(视图) :
负责把 Model 的数据展示出来,不包含业务逻辑。
-
Controller(控制器) :
接收用户输入,协调 Model 更新,并选择/驱动 View 刷新。
一、非MVC写法
1.1 例子
一个修改金币的例子
public class NotMvcDemo { private int coin = 0; private TextMeshProUGUI coinText; private void AddCoin(int addCount) { coin+=addCount; coinText.text = $"{addCount}"; } }
这个管理类里同时包含了:
1.状态(或数据),以下都称为状态,即金币数量coin;
2.包含了显示UI coinText;
- 包含了修改方法AddCoin,更改了状态变化和显示变化;
状态、UI、控制方法耦合在一个文件里。
1.2 可优化地方
我们要让状态变化 和 显示变化 和 修改方法三者分离。
让状态变化 成为驱动整个流程的核心,而不是用修改方法命令一样的改变状态和显示。
二、MVC改造
2.1 先将最简单的View独立
[Serializable] public class MvcDemoView {
public TextMeshProUGUI coinText; public Button addCoinBtn; // 调用方法修改view public void RenderCoinText(int currentCoint) { if (coinText!= null) { coinText.text = $"{currentCoint}"; } } }
2.2 状态
Serializable
public class MvcDemoData
{
// SYMvcObservable是封装的数据变化通知,看2.3说明,当对值set就发通知
public SYMvcObservable<int> coin = new(); public void AddCoint(int addCoinCount) { coin.Value += addCoinCount; }}
2.3 数据变化通知
我们的目的是状态中的数据变化了,View就要随之更改,所以封装一个类做到这一点:
public sealed class SYMvcObservable<T> { private T _value; // 数据 public event Action<T> Changed; // 数据变化set,就执行Action public SYMvcObservable(T initial = default) => _value = initial; public T Value { get => _value; set { if (Equals(_value, value)) return; _value = value; Changed?.Invoke(_value); } } }
我们用SYMvcObservable对一条数据做一个封装,当数据set改变的时候,就执行Changed。
2.4 让Changed和修改View绑定
public static class BindUtil { /// <summary> /// 订阅 Observable 变化并立即渲染一次;自动把解绑动作登记到 disposer。 /// </summary> public static void Bind<T>(this SYMvcDisposer disposer, SYMvcObservable<T> obs, Action<T> render, bool renderImmediately = true) { if (obs == null || render == null) return; obs.Changed += render; disposer.Add(() => obs.Changed -= render); if (renderImmediately) render(obs.Value); }}
2.5 SYMvcDisposer类存储data和view的绑定,并且在合适的时机释放
// 缓存起来,在合适的时候统一释放 public sealed class SYMvcDisposer : IDisposable { private readonly List<Action> _undos = new(); public void Add(Action undo) { if (undo != null) _undos.Add(undo); } public void Dispose() { for (int i = _undos.Count - 1; i >= 0; i--) _undos[i]?.Invoke(); _undos.Clear(); } }
2.6 在Controller中创建data和view的绑定,和释放。
using System.Collections; using System.Collections.Generic; using SiYangMVC.Runtime; using UnityEngine; public class AddCointController : MonoBehaviour,IMvcController { private AddCoinModel _data = new(); [SerializeField] private AddCoinView _view; // 暂时存储绑定关系,方便在某个时刻释放。 private SYMvcDisposer _disposer; private void OnEnable() { Bind(); } private void OnDisable() { Unbind(); } public void Bind() { _disposer = new SYMvcDisposer(); _disposer.Bind(_data.coin , _view.RenderCoinText); // 对Button的绑定 _disposer.OnClick(_view.addCoinBtn,()=>SetTouchTipVisible(5)); } public void Unbind() { _disposer?.Dispose(); _disposer = null; } //----------api------------- public void SetTouchTipVisible(int addCoint) { _data.AddCoint(addCoint); } }
MVC的C指Controller,在Controller中更新model,再更新view。
我们实现了一个数据绑定,更新model后,model会利用绑定的Action更新View。