一句话定义:PureMVC是一个轻量级的、基于经典MVC模式的应用程序框架,核心目标是将代码按职责分离,实现高内聚低耦合。
PureMVC框架链接puremvc.org/ 找到对应的语言下载即可
csharp
kotlin 体验AI代码助手 代码解读复制代码// 典型“上帝类”写法 —— 所有逻辑堆在一个MonoBehaviour里
public class BattleManager : MonoBehaviour
{
public UIManager ui;
public NetworkManager network;
public DataManager data;
void OnEnemyDie()
{
ui.ShowVictoryPanel();
data.AddExp(100);
network.SendBattleResult();
// 越往后越难维护...
}
}问题:
角色定位:整个框架的“前台总机”,所有对外操作都通过它。
(简单来说就是Mediator、Proxy、Command之间都不会互相调用,因为这样会非常的复杂,不便于维护,而是统一通过调用Facade里的类似GetProxy()、GetMediator()函数来间接获取目标引用,这样通过在Facade实现统一的接口来让外部调用的方法很好的解决了模块间直接引用导致的逻辑混乱)
csharp
scss 体验AI代码助手 代码解读复制代码// 标准用法:项目里写一个自己的Facade继承基类
public class GameFacade : Facade
{
// 单例访问
public static GameFacade Instance => instance as GameFacade;
// 启动框架
public void Startup()
{
// 注册Proxy
RegisterProxy(new UserProxy());
RegisterProxy(new BagProxy());
// 注册Command(绑定事件与处理逻辑)
RegisterCommand(NotificationName.LOGIN, () => new LoginCommand());
RegisterCommand(NotificationName.BAG_ADD_ITEM, () => new AddItemCommand());
// 注册Mediator(通常由UIManager在打开界面时动态注册)
}
}
// 业务代码中调用
GameFacade.Instance.SendNotification(NotificationName.LOGIN, userData);核心职责:
角色定位:管理某一类数据,以及操作这些数据的方法。
csharp
csharp 体验AI代码助手 代码解读复制代码// 数据代理:管理玩家背包
public class BagProxy : Proxy
{
// Proxy名称(用于跨模块获取)
public new const string NAME = "BagProxy";
// 实际数据
public List<Item> Items { get; private set; } = new List<Item>();
// 业务方法
public void AddItem(Item item)
{
Items.Add(item);
// 数据变了,发通知告诉UI更新
SendNotification(NotificationName.BAG_UPDATE, Items.Count);
}
public bool HasItem(int itemId)
{
return Items.Any(item => item.Id == itemId);
}
public void RemoveItem(int itemId)
{
Items.RemoveAll(item => item.Id == itemId);
SendNotification(NotificationName.BAG_UPDATE);
}
}
// 其他地方获取并使用
var bagProxy = GameFacade.Instance.RetrieveProxy(BagProxy.NAME) as BagProxy;
bagProxy.AddItem(new Item(10001, "红药水"));关键理解:
角色定位:UI界面和PureMVC系统之间的“翻译官”。
csharp
csharp 体验AI代码助手 代码解读复制代码// 中介者:管理一个背包面板
public class BagMediator : Mediator
{
public new const string NAME = "BagMediator";
// 持有的UI组件引用
private BagPanel bagPanel;
// 构造函数:传入View组件
public BagMediator(BagPanel panel) : base(NAME)
{
bagPanel = panel;
bagPanel.OnItemClick += HandleItemClick; // 监听UI事件
}
// 声明感兴趣的通知(订阅)
public override IList<string> ListNotificationInterests()
{
return new List<string>
{
NotificationName.BAG_UPDATE,
NotificationName.ITEM_USE_RESULT
};
}
// 处理通知
public override void HandleNotification(INotification notification)
{
switch (notification.Name)
{
case NotificationName.BAG_UPDATE:
UpdateBagView();
break;
case NotificationName.ITEM_USE_RESULT:
ShowUseResult(notification.Body as string);
break;
}
}
// 视图更新逻辑
private void UpdateBagView()
{
var bagProxy = Facade.RetrieveProxy(BagProxy.NAME) as BagProxy;
bagPanel.RefreshItems(bagProxy.Items);
}
// UI事件响应
private void HandleItemClick(Item item)
{
// Mediator不处理业务逻辑,发个通知交给Command
SendNotification(NotificationName.USE_ITEM, item.Id);
}
// Mediator销毁时的清理
public override void OnRemove()
{
bagPanel.OnItemClick -= HandleItemClick;
base.OnRemove();
}
}关键理解:
角色定位:执行具体的业务操作,可以调用多个Proxy协同工作。
csharp
scss 体验AI代码助手 代码解读复制代码// 简单命令:使用物品
public class UseItemCommand : SimpleCommand
{
public override void Execute(INotification notification)
{
int itemId = (int)notification.Body;
var bagProxy = Facade.RetrieveProxy(BagProxy.NAME) as BagProxy;
var roleProxy = Facade.RetrieveProxy(RoleProxy.NAME) as RoleProxy;
if (bagProxy.HasItem(itemId))
{
bagProxy.RemoveItem(itemId);
roleProxy.AddHp(100);
// 发通知让UI刷新
SendNotification(NotificationName.ROLE_HP_UPDATE);
SendNotification(NotificationName.USE_ITEM_SUCCESS, itemId);
}
else
{
SendNotification(NotificationName.USE_ITEM_FAIL, "物品不存在");
}
}
}
// 宏命令:执行一系列命令(比如登录流程)
public class LoginMacroCommand : MacroCommand
{
public override void InitializeMacroCommand()
{
AddSubCommand(() => new CheckVersionCommand()); // 1. 检查版本
AddSubCommand(() => new ConnectServerCommand()); // 2. 连接服务器
AddSubCommand(() => new AuthCommand()); // 3. 身份验证
AddSubCommand(() => new LoadRoleDataCommand()); // 4. 加载角色数据
AddSubCommand(() => new EnterGameCommand()); // 5. 进入游戏
}
}Command的特点:
角色定位:模块间传递消息的信封。
csharp
csharp 体验AI代码助手 代码解读复制代码// 定义通知名称常量(避免字符串硬编码)
public static class NotificationName
{
public const string LOGIN = "login";
public const string LOGOUT = "logout";
public const string BAG_UPDATE = "bag_update";
public const string USE_ITEM = "use_item";
public const string USE_ITEM_SUCCESS = "use_item_success";
}
// 发送通知的三种重载
SendNotification(NotificationName.LOGIN); // 只有名称
SendNotification(NotificationName.LOGIN, loginData); // 带body(数据)
SendNotification(NotificationName.LOGIN, loginData, "extra"); // 带body和typeNotification与C#事件的对比:
特性 | C#事件 | PureMVC Notification |
|---|---|---|
解耦程度 | 中等(需要持有发布者引用) | 高(完全不知道谁在收) |
调试难度 | 容易跟踪 | 难(字符串匹配) |
性能 | 快(直接委托调用) | 稍慢(反射+装箱拆箱) |
跨模块通信 | 需要统一的事件总线 | 天然支持 |
把上面所有组件串起来,看一个完整的登录流程:
csharp
typescript 体验AI代码助手 代码解读复制代码// 1. 启动框架(GameManager中)
GameFacade.Instance.Startup();
// 2. UI按钮点击 -> 打开登录面板时注册Mediator
LoginPanel panel = UIManager.Open<LoginPanel>();
GameFacade.Instance.RegisterMediator(new LoginMediator(panel));
// 3. 用户点击登录按钮 -> Mediator监听到UI事件
public class LoginMediator : Mediator
{
private LoginPanel panel;
public LoginMediator(LoginPanel panel) : base("LoginMediator")
{
this.panel = panel;
panel.OnLoginClick += (user, pwd) =>
SendNotification(NotificationName.LOGIN, new LoginData(user, pwd));
}
}
// 4. Command处理登录业务
public class LoginCommand : SimpleCommand
{
public override void Execute(INotification notification)
{
var loginData = notification.Body as LoginData;
var userProxy = Facade.RetrieveProxy(UserProxy.NAME) as UserProxy;
// 调用网络层发送登录请求
NetworkManager.Instance.Login(loginData.User, loginData.Pwd, (success, msg) =>
{
if (success)
{
userProxy.SetUserInfo(msg);
SendNotification(NotificationName.LOGIN_SUCCESS);
SendNotification(NotificationName.OPEN_MAIN_PANEL);
}
else
{
SendNotification(NotificationName.LOGIN_FAIL, msg);
}
});
}
}
// 5. 登录成功 -> 关闭登录界面,打开主界面
public class LoginSuccessCommand : SimpleCommand
{
public override void Execute(INotification notification)
{
// 移除登录Mediator
Facade.RemoveMediator("LoginMediator");
// 打开主界面并注册其Mediator
MainPanel mainPanel = UIManager.Open<MainPanel>();
Facade.RegisterMediator(new MainMediator(mainPanel));
}
}原则:Mediator持有MonoBehaviour的引用,但Mediator本身不继承MonoBehaviour。
csharp https://bjs.my.canvasite.cn/ https://tj.my.canvasite.cn/ https://shp.my.canvasite.cn/ https://zqs.my.canvasite.cn/
kotlin 体验AI代码助手 代码解读复制代码// 错误:让Mediator继承MonoBehaviour
public class BadMediator : MonoBehaviour, IMediator { } // ❌
// 正确:Mediator是纯C#类
public class GoodMediator : Mediator // 不继承MonoBehaviour ✓
{
private GoodPanel panel; // 持有MonoBehaviour引用
}组件 | 创建时机 | 销毁时机 |
|---|---|---|
Facade | 游戏启动时 | 游戏结束时 |
Proxy | 游戏启动时注册 | 游戏结束时 |
Command | 每次执行时new | 执行完后销毁 |
Mediator | 打开UI时注册 | 关闭UI时移除 |
ListNotificationInterests返回缓存列表,不要每次new原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。