yukamu 发表于 2022-5-10 21:11

Unity中使用简易MVC详解

MVC概述


[*]MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,一种软件设计典范。
[*]根据名称定义在MVC中可以分为三层,也就是Model 层,View 层,Controller 控制层
[*]Model(模型) :“数据模型”(Model)用于封装与应用程序的业务逻辑相关的数据以及对数据的处理方法。模型有对数据直接访问的权力,例如对数据库的访问。模型不依赖视图和控制器,也就是说,模型不关心它会被如何显示或是如何被操作。但是模型中数据的变化一般会通过一种刷新机制被公布。为了实现这种机制,那些用于监视此模型的视图必须事先在此模型上注册,从而,视图可以了解在数据模型上发生的改变。
View(视图) :视图层能够实现数据有目的的显示(理论上,这不是必需的)。在视图中一般没有程序上的逻辑。为了实现视图上的刷新功能,视图需要访问它监视的数据模型(Model),因此应该事先在被它监视的数据那里注册。
Controller(控制器) :控制器起到不同层面间的组织作用,用于控制应用程序的流程。它处理事件并作出响应。事件包括用户的行为和数据模型上的改变
下图展现了MVC不同层的类型和功能:



<hr/>Unity中的MVC


[*]在unity中常见并在大型项目中常用到的的ui框架有基于MVVM的uFrame、基于MVC的PureMVC和基于MVCS的StrangeIoC,三者各有优劣。关于这三个框架及MVVM和MVCS的结构我们之后再说,这里通过代码来了解一下在Unity中的MVC:
mvc核心控制类:

MVC.csusing UnityEngine;
using System;
using System.Collections.Generic;
/// <summary>
/// puremvc核心控制器
/// </summary>
public class MVC : MonoBehaviour
{
    private static Dictionary<string, Model> Models = new Dictionary<string, Model>();
    private static Dictionary<string, View> Views = new Dictionary<string, View>();
    private static Dictionary<string, Type> Commands = new Dictionary<string, Type>();

    #region Model Method
    /// <summary>
    /// 注册model
    /// </summary>
    /// <param name="model">Model.</param>
    public static void RegisterModel(Model model)
    {
      if (!Models.ContainsKey(model.Name))
      {
            Models.Add(model.Name, model);
      }
    }

    public static void UnRegisterModel(Model model)
    {
      if (Models.ContainsKey(model.Name))
      {
            Models.Remove(model.Name);

      }
    }

    public static T GetModel<T>(string name) where T : Model
    {
      foreach (string n in Models.Keys)
      {
            if (n == name)
            {
                return Models as T;
            }
      }
      return null;
    }

    #endregion

    #region View Method
    /// <summary>
    /// 注册view
    /// </summary>
    /// <param name="view">View.</param>
    public static void RegisterView(View view)
    {
      if (!Views.ContainsKey(view.Name))
      {
            Views.Add(view.Name, view);
      }
    }

    public static void UnRegisterView(View view)
    {
      if (Views.ContainsKey(view.Name))
      {
            Views.Remove(view.Name);
            view.RegisterNotification();

      }
    }

    public static T GetView<T>(string name) where T : View
    {
      foreach (string n in Views.Keys)
      {
            if (n == name)
            {
                return Views as T;
            }
      }
      return null;
    }
    #endregion

    #region Command Method
    /// <summary>
    /// 注册controller
    /// </summary>
    /// <param name="name">Name.</param>
    /// <param name="type">Type.</param>
    public static void RegisterCommand(string name, Type type){
      if (!Commands.ContainsKey(name)){
            Commands.Add(name, type);
      }

    }

    public static void UnRegisterCommand(string name, Type type){
      if(Commands.ContainsKey(name)){
            Commands.Remove(name);
      }
    }

    public static void HandleNotifition(string name, object data = null){
      //判断事件是否存在,如果存在则实例化对象并执行事件
      if(Commands.ContainsKey(name)){
            Controller command = Activator.CreateInstance(Commands) as Controller;
            command.Execute(data);
      }
      //判断视图是否关注该事件,如果关注则执行事件
      foreach(View view in Views.Values){
            if (view.ContainsNotification(name)){
                view.HandleNotification(name, data);
            }
      }
    }
    #endregion
}
Model基类

Model.cs:using UnityEngine;
/// <summary>
/// mov中的Model基类
/// </summary>
public abstract class Model{
    /// <summary>
    /// model的名字
    /// </summary>
    /// <value>The name.</value>
    public abstract string Name { get; }

    /// <summary>
    /// 发送通知
    /// </summary>
    /// <param name="name">事件名称</param>
    /// <param name="data">事件执行参数</param>
    public virtual void SendNotification(string name, object data = null){
      MVC.HandleNotifition(name, data);
    }

}View基类

View.csusing UnityEngine;
using System.Collections.Generic;
/// <summary>
/// mvc中的View基类
/// </summary>
public abstract class View{
    /// <summary>
    /// View的名字
    /// </summary>
    /// <value>The name.</value>
    public abstract string Name { get; }
    /// <summary>
    /// 发送通知
    /// </summary>
    /// <param name="name">事件名称</param>
    /// <param name="data">事件执行参数</param>
    public virtual void SendNotification(string name, object data = null){
      MVC.HandleNotifition(name, data);
    }

    /// <summary>
    /// 获取模型model
    /// </summary>
    /// <returns>The model.</returns>
    /// <param name="name">model名称</param>
    /// <typeparam name="T">The 1st type parameter.</typeparam>
    public T GetModel<T>(string name) where T : Model{
      return MVC.GetModel<T>(name) as T;
    }

    /// <summary>
    /// 保存通知
    /// </summary>
    private List<string> InterestNotification = new List<string>();

    public virtual void RegisterNotification(){

    }
    public bool ContainsNotification(string name){
      return InterestNotification.Contains(name);
    }
    /// <summary>
    /// 处理事件
    /// </summary>
    /// <param name="name">事件名称</param>
    /// <param name="data">事件参数</param>
    public virtual void HandleNotification(string name, object data = null){

    }

}Controller基类

Controller.csusing UnityEngine;
using System;

/// <summary>
/// mvc中的Controller基类
/// </summary>
public abstract class Controller
{
    /// <summary>
    /// Controller的名字
    /// </summary>
    /// <value>The name.</value>
    public abstract string Name { get; }

    public T GetModel<T>(string name) where T : Model
    {
      return MVC.GetModel<T>(name);
    }
    public T GetView<T>(string name) where T : View
    {
      return MVC.GetView<T>(name);
    }

    public void RegisterView(View view)
    {
      MVC.RegisterView(view);
    }

    public void RegisterModel(Model model)
    {
      MVC.RegisterModel(model);
    }

    public void RegisterCommand(string name, Type type)
    {
      MVC.UnRegisterCommand(name, type);
    }
    /// <summary>
    /// 发送通知
    /// </summary>
    /// <param name="data">事件执行参数</param>
    public abstract void Execute(object data = null);
}写在最后


[*]这里只是为了介绍unity中mvc的简单使用,但于我看来,在游戏项目中mvc框架并不非常适用,MVC是ui专用的模式,游戏不同于web前端,不同类型的游戏其架构相差非常之大(比如棋牌类游戏,rpg游戏,moba类游戏,跑酷类游戏之间的差别) ,所以游戏中mvc不同的层很难有非常清晰的定义。并不是说MVC在游戏项目中完全没用,但只有它还远远不够。游戏项目最合理的方式是由主程根据项目需求制定一套新的结构和各部分的依赖关系,并事先想好各部分的扩展和通信方式。

HuldaGnodim 发表于 2022-5-10 21:12

同意写在最后的观点。以前写游戏编辑器时,经常使用mvc。但是做游戏时,对于UI部分也没用上类似的模式。更常用的是基于数据的驱动,基于事件的响应以及对于UI场景管理,资源管理。很难说是什么模式,但就是实用,就是效率高,哈哈
页: [1]
查看完整版本: Unity中使用简易MVC详解