StrangeIoC MVSC框架模块说明
1.Root
1 2 3 4 5 6 7 8 9 10
| using strange.extensions.context.impl;
public class WatchMenuRoot : ContextView { private void Awake() { context = new WatchMenuContext(this, true); context.Start(); } }
|
该脚本负责启动MVCS框架,需要绑定到一个GameObject上作为容器,所有需要使用StrangeIoC提供注入功能的模块都需添加到该容器内。
2.Context
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| using strange.extensions.context.api; using strange.extensions.context.impl; using UnityEngine;
public class WatchMenuContext : MVCSContext { public WatchMenuContext() : base() {
} public WatchMenuContext(MonoBehaviour view, bool autoStartup) : base(view, autoStartup) {
} protected override void mapBindings() { mapModel(); mapView(); mapCommand(); commandBinder.Bind(ContextEvent.START).To<WatchMenuStartupCommand>().Once(); } private void mapModel() { injectionBinder.Bind<IModel>().To<Model>().ToSingleton(); injectionBinder.Bind<IService>().To<Service>().ToSingleton(); } private void mapView() { mediationBinder.Bind<View>().To<Mediator>(); } private void mapCommand() { commandBinder.Bind(NotificationCenter.GET_STUFF_LIST).To<Command>(); } }
|
该脚本的作用是关联整个MVSC的模块,因为各个模块之间解耦,Context则进行模块耦合,主要进行模块绑定
injectionBinder.Bind
1
| injectionBinder.Bind<IModel>().To<Model>().ToSingleton();
|
把Model作为单例绑定到IModel上,每次通过[Inject]标签注入IModel对象时,获得的都是同一个Model实例
mediationBinder.Bind
1
| mediationBinder.Bind<View>().To<Mediator>();
|
把Mediator绑定到View上,在向GameObject添加View脚本时会自动创建Mediator对象并绑定到该物体
commandBinder.Bind
1
| commandBinder.Bind(NotificationCenter.GET_STUFF_LIST).To<Command>();
|
把NotificationCenter.GET_STUFF_LIST绑定到Command上,当派发上述指令时,会创建一个Command实例并运行
commandBinder.Bind(ContextEvent.START)
1
| commandBinder.Bind(ContextEvent.START).To<WatchMenuStartupCommand>().Once();
|
Once()立即执行并解除绑定
3.StartupCommand
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| using strange.extensions.command.impl; using strange.extensions.context.api; using UnityEngine;
public class WatchMenuStartupCommand : EventCommand { [Inject(ContextKeys.CONTEXT_VIEW)] public GameObject contextView { get; set; }
GameObject go; public override void Execute() { go = contextView.transform.Find("menu-stuff").gameObject; go.AddComponent<MenuStuffView>(); } }
|
绑定了Root脚本的GameObject注入进来,将View添加到各个对应的物体上,同时Mediator也会同步添加。
4.View
- 视图类负责显示相关的逻辑,一般无法访问数据同时也不会调用请求接口,只通过注入的IEventDispatcher与Mediator进行通讯
1 2 3 4 5 6 7 8 9 10 11
| public class MenuHomeView : View {
[Inject(ContextKeys.CONTEXT_DISPATCHER)] public IEventDispatcher dispatcher { get; set; }
public void Init() { } }
|
- 中介类作为通信中心,负责消息转发,可以将View的消息转发给其他模块,也可以接收其他模块的消息,然后通知到View
- 通过注入拿到View对象
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class MenuHomeMediator : EventMediator { [Inject] public MenuHomeView view { get; set; } public override void OnRegister() { view.Init(); } public override void OnRemove() {
} }
|
6.Command
- 该类用于数据请求和数据处理,执行具体的代码(工具人)
- 通过注入拿到Model和Service对象
- 如果有异步操作,需要Retain() Release()配合,保证不被垃圾回收销毁
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public class MenuRoomCommand : EventCommand { [Inject] public IRoomDataModel model { get; set; } [Inject] public IRoomDataService service { get; set; } public override void Execute() { Retain(); dispatcher.AddListener(NotificationCenter.GET_ROOM_LIST_MENU, GetRoomListHandler); } private void GetRoomListHandler() { dispatcher.RemoveListener(NotificationCenter.GET_ROOM_LIST_MENU, GetRoomListHandler); service.AsyncGetData(); Release(); }
}
|
7.Model&Service
- Model用于数据存储
- Service用于远程请求
8.工作中遇到过的问题
- 禁止从service向command发消息,否则会生成多个command监听事件导致事件重复触发。例如command监听mediator的消息执行了一个函数,该函数内有service的函数且在函数内service向command发送消息,导致生成两个command对象。
- 跨上下文context需要在绑定函数内进行非空判断,否则返回场景会报错。
- 如果View成功绑定到物体上,但Mediator未能正常生成并加载,需要保证View所在物体必须是Root的子物体。
- 不能在View中注入其他View,否则会导致View绑定失败。