简介
多核版本允许多个PureMVC应用运行在同一个虚拟机;模块化编程
在PureMVC实现的经典MVC元设计模式中,这三部分由三个单例模式类管理,分别是Model、View和Controller。三者合称为核心层或核心角色。
PureMVC,就如同它的名字是,它是一个纯粹的小巧的MVC框架,支持多语言。
PureMVC有一个名为Mediator的构造,顾名思义,它就是Mediator模式的实现,充当视图API和程序其余部分的API之间的中介。这是PureMVC实现MVC架构视图部分的关键构造。引入它是为了减少应用和视图之间的依赖,从而降低整个系统的耦合程度
框架优点:
PureMVC是多种设计模式的结合体:V和C之间会实现观察者模式,M内部会实现单例模式,C在派发任务时会实现Command模式。
MVC模式对软件的高可扩展性和高可维护性做出了巨大的贡献,使得MVC模式成为中等甚至大规模软件的常用框架,且经历了20余年仍旧在软件开发领域流行并通用,足可见MVC模式的经典。
MVC框架缺点:
- Controller:控制器,包含了项目的业务逻辑。 大多数人习惯于什么都往Controller里写,最后一个Controller超过1000行代码是司空见惯的事。所以关于传统MVC的第一个痛点就是,Controller过于臃肿。
- Model:模型,包含了项目的数据模型。MVC定义之初,Model是核心,旨在使得同一个Model可以被复用到多个项目或者被复用到同一个项目的不同模块之中。但是在实际项目中,Model还承载着纯Model层内部的运算的工作,但是运算部分会项目的不同而有所区别,因此与项目的适配反而成为了Model可复用的枷锁。所以关于传统MVC的第二个痛点就是,Model变得不可复用。
- View:视图,包含了项目所有的UI组件。视图本身没有什么好被大家诟病的,但是由于MVC中对于View和Controller界限的模糊界定造成了使用者在写代码的时候会觉得这部分代码放在View或者Controller里都可以的情况。例如事件的处理,组件的组合等。所以关于传统MVC的第三个痛点就是,View概念的模糊 。
- 灵活度过高,要清晰控制一个事务过程不容易。 这个是由通知无向性决定的,很难确定谁来监听某一个通知,通知不利于调试。
- 代码冗余比较大,Mediator、Proxy等继承类的冗余代码,但是ActionScript不支持Generics以及Reflection能力弱,使得难以消减代码。
初始化
首先Facade是一个单例。在它的构造函数里除了单例应有的部分外,还有一句initializeFacade() 具体的实现是
protected function initializeFacade( ):void {
initializeModel();
initializeController();
initializeView();
}
很明显,这里揭示了Facade主要干3件事情,初始化Model,Controller,View,而这三个都是单例
Model用于保存所有的Proxy,View用于保存所有的Mediator还可以注册一些对notification的监听,而Controller主要是保持一些Command。这些类提供了注册的方法也提供了查询的方法。那么Facade这个类本身也提供了对于Proxy,Mediator,Controller的访问接口。这正符合Facade的本意:将众多的对外接口统一起来,但是也不屏蔽底层的接口。
然后例子中的程序复写了其中一个initializeContrller()的方法
override protected function initializeController():void
{
super.initializeController();
registerCommand( ApplicationConstants.NOTE_STARTUP,StartupCommand);
registerCommand( ApplicationConstants.NOTE_LOGIN, LoginCommand);
}
建立了两对notification和Command之间的映射关系。
最简项目开发
Hello World项目总体开发步骤:
- 一、下载框架插件与搭建基础环境。
- 二、建立UI界面与定义基础类。
- 三、初步应用PureMVC。
一、下载框架插件与搭建基础环境
下载C#版本的PureMVC 框架源码工程。
建立一个空unity项目。
导入框架文件
二、建立UI界面与定义基础类
1: 建立UGUI ,
创建显示与按钮两个控件。
2: 定义基础类与脚本
3:确定命名空间、各个脚本的功能与继承类等
三、初步应用PureMVC
1: 首先定义数据类与“数据代理”类。
// Model数据实体类,存储原始数据
public class DataEntityModel
{
private int _Level = 0;
/// <summary>
/// 玩家等级
/// </summary>
public int Level { get => _Level; set => _Level = value; }
}
// Model模型层的数据逻辑层: 数据模型代理类,数据的操作
public class DataProxyModel : Proxy
{
//声明本类的名称
public new const string NAME = "DataProxyModel";
//引用“实体类”
private DataEntityModel _MyDataModel = null;
/// <summary>
/// 构造函数
/// </summary>
public DataProxyModel() : base(NAME)
{
_MyDataModel = new DataEntityModel();
}
/// <summary>
/// 增加等级
/// </summary>
/// <param name="addNumber">增加的等级数量</param>
public void AddLevel(int addNumber)
{
//把参数累加到“实体类”中
_MyDataModel.Level += addNumber;
//把数据变化发消息给“视图层”
SendNotification("Msg_AddLevel", _MyDataModel);
}
}
2: 然后定义视图类
A) 当注册的视图层按钮被点击时,发送“消息”到控制层。
public class DataMediatorView : Mediator
{
//定义名称
public new const string NAME = "DataMediatorView";
//定义两个控件
private Text TxtLevel;
private Button BtnDisplayLevelNum;
/// <summary>
/// 构造函数
/// </summary>
/// <param name="goRootNode">UI根节点</param>
public DataMediatorView(GameObject goRootNode)
{
//视图类名称
//MediatorViewName = mediatorViewName;
//获取控件
TxtLevel = goRootNode.transform.Find("Text_DisplayNum").gameObject.GetComponent<Text>();
BtnDisplayLevelNum = goRootNode.transform.Find("Btn_Count").gameObject.GetComponent<Button>();
//注册按钮点击事件
BtnDisplayLevelNum.onClick.AddListener(OnClickAddingLevelNumber);
}
//用户点击事件
private void OnClickAddingLevelNumber()
{
//定义消息,发消息到”控制层“
SendNotification("Reg_StartDataCommand");
}
B) 定义本视图类,允许接收的消息名称集合,以及对应的处理。
{
IList<string> listResult = new List<string>();
//可以接收多条消息
listResult.Add("Msg_AddLevel");
return listResult;
}
public override void HandleNotification(INotification notification)
{
//base.HandleNotification(notification);
switch (notification.Name)
{
case "Msg_AddLevel":
//把模型层发来的消息内容,显示给控件
DataEntityModel myData = notification.Body as DataEntityModel;
TxtLevel.text = myData.Level.ToString();
break;
default:
break;
}
}
3: 定义控制类
public class DataCommandControl : SimpleCommand
{
public override void Execute(INotification notification)
{
//base.Execute(notification);
//调用数据模型层的“增加等级”方法
DataProxyModel datapro = (DataProxyModel)Facade.RetrieveProxy(DataProxyModel.NAME);
datapro.AddLevel(10);
}
}
4: 通过PureMVC 框架注册方法(RegisterXXX)
把MVC的三个层进行关联绑定。
public class ApplicationFacade : Facade
{
/// <summary>
/// 构造函数
/// </summary>
/// <param name="goRootNode">UI根节点</param>
public ApplicationFacade(GameObject goRootNode)
{
//MVC三层的关联绑定
//M模型层注册
RegisterProxy(new DataProxyModel());
//V视图层注册
RegisterMediator(new DataMediatorView(goRootNode));
//C控制层注册 (视图层"命令消息"与控制层类的对应绑定)
RegisterCommand("Reg_StartDataCommand", typeof(DataCommandControl));
}
}
5: 定义入口类 StartGameControl
public class StartGame : MonoBehaviour
{
private void Start()
{
//启动框架
new ApplicationFacade(this.gameObject);
}
}
start方法来作为整个程序的开始,发出一个表示开始的notification,这个notification则触发了StartupCommand,这是一个多条Command的执行序列。分别是Model和View的准备command,它们完成了LoginProxy的注册,LoginMediator的注册并且把LoginPanel显式在舞台上等待用户输入
特点
单例模式类——Facade,Facade提供了与核心层通信的唯一接口,以简化开发复杂度。
Model 与 Proxy
Model保存对Proxy对象的引用,Proxy负责操作数据模型,与远程服务通信存取数据。
这样保证了Model层的可移植性。
View 与 Mediator
View保存对Mediator对象的引用。由Mediator对象来操作具体的视图组件(View Component,例如Flex的DataGrid组件),包括:添加事件监听器,发送或接收Notification ,直接改变视图组件的状态。
这样做实现了把视图和控制它的逻辑分离开来。
Controller 与 Command
Controller保存所有Command的映射。Command类是无状态的,只在需要时才被创建。
Command可以获取Proxy对象并与之交互,发送Notification,执行其他的Command。经常用于复杂的或系统范围的操作,如应用程序的“启动”和“关闭”。应用程序的业务逻辑应该在这里实现。
Facade 与 Core
Facade类应用单例模式,它负责初始化核心层(Model,View和Controller),并能访问它们的Public方法。
这样,在实际的应用中,你只需继承Facade类创建一个具体的Facade类就可以实现整个MVC模式,并不需要在代码中导入编写Model,View和Controller类。
Proxy、Mediator和Command就可以通过创建的Facade类来相互访问通信。
Observer 与 Notification
PureMVC的通信并不采用Flash的EventDispatcher/Event,因为PureMVC可能运行在没有Flash Event和EventDispatcher类的环境中,它的通信是使用观察者模式以一种松耦合的方式来实现的。
你可以不用关心PureMVC的Observer/Notification机制是怎么实现的,它已经在框架内部实现了。你只需要使用一个非常简单的方法从Proxy, Mediator, Command和Facade发送Notification,甚至不需要创建一个Notification实例。
Notification可以被用来触发Command的执行
Facade保存了Command与Notification之间的映射。当Notification(通知)被
发出时,对应的Command(命令)就会自动地由Controller执行。Command实现复杂的交互,降低View和Model之间的耦合性。
Mediator发送、声明、接收Notification
当用View注册Mediator时,Mediator的listNotifications方法会被调用,以数组形式返回该Mediator对象所关心的所有Notification。
之后,当系统其它角色发出同名的Notification(通知)时,关心这个通知的Mediator都会调用handleNotification方法并将Notification以参数传递到方法。
Proxy发送,但不接收Notification
在很多场合下Proxy需要发送Notification(通知),比如:Proxy从远程服务接收到数据时,发送Notification告诉系统;或当Proxy的数据被更新时,发送Notification告诉系统。
如果让Proxy也侦听Notification(通知)会导致它和View(视图)层、Controller(控制)层的耦合度太高。
View和Controller必须监听Proxy发送的Notification,因为它们的职责是通过可视化的界面使用户能与Proxy持有的数据交互。
不过对View层和Controller层的改变不应该影响到Model层。