-
commandBinder
- 命令绑定
前面提到,作者为我们扩展的是MVCS版本的strange框架,先看一张图
M、V、C、S分别对应Models、view、controller、services。commandBinder即用来将一条指令与控制器(controller)绑定起来。比如:
commandBinder.Bind("煮粥").To<CookCongeeCommand>();
CookCongeeCommand类如下:
public class CookCongeeCommand
{
1. 加水
2. 加米
3. 开火
...
}
这样,每次我们收到“煮粥”的命令时就会去执行CookCongeeCommand
。
明白原理了,我们就继续看如何具体使用commandBinder
。
上一篇提到,绑定应该在上下文中进行,即MVCSContext类(或其子类)中进行,所以我们只需要将绑定代码写道上下文类的mapBindings
方法中即完成绑定。
前面说收到“煮粥”的命令时就会去执行CookCongeeCommand
。但类无法执行,执行的只能是方法,所以一个命令类是什么样的呢?
1.写一个命令类首先要引用了strange.extensions.command.impl
命名空间。
2.我们自己的命令类要继承自EventCommand
,(实际上只需要继承自ICommand
接口)
所以,CookCongeeCommand
应该是这样:
using strange.extensions.command.impl;
public class CookCongeeCommand : EventCommand
{
[Inject]
public cook cook;//厨师
public override void Execute()
{
cook.加水();
cook.加米();
cook.开火();
}
}
触发一条指令时框架会自动创建命令对象并按照:注入->执行(Excute() 方法)->销毁的顺序运行。
commandBinder
有以下几种用法:
//绑定指令和命令类
commandBinder.Bind(ServerEvent.POST_SCORE).To<PostScoreCommand>();
//绑定多个命令类
commandBinder.Bind(GameEvent.HIT).To<DestroyEnemyCommand>().To<UpdateScoreCommand>();
//解除绑定
commandBinder.Unbind(ServerEvent.POST_SCORE);
//执行一次命令后,命令类实例自动被销毁
commandBinder.Bind(GameEvent.HIT).To<DestroyEnemyCommand>().Once();
//绑定命令组
commandBinder.Bind(GameEvent.HIT).InSequence() .To<CheckLevelClearedCommand>() .To<EndLevelCommand>() .To<GameOverCommand>();
关于命令组:命令组是一串命令,当执行到某个命令失败后,会自动跳出执行流(后面的命令不在执行)。也可以在命令中手动调用Fail()方法强制跳出执行流。
现在,接收指令的人准备好了,那么谁通过什么方式发送指令呢?
在框架中有两种方式发送指令,一,使用EventDispatcher发送指令。二,使用Signal发送指令。Signal是作者推出用来替代EventDispatcher的方式,更安全,更少GC。
- 使用
EventDispatcher
发送指令。
EventDispatcher
类似于观察者模式中的subject
,所有的指令都是通过EventDispatcher
对象发送的。该对象是一个全局对象。
接着上面的例子,顾客需要发送一条“煮粥”的指令:
public class customer
{
[Inject]
public IEventDispatcher dispatcher{get;set;}
void Order()
{
dispatcher.Dispatch("煮粥");//发送指令
}
}
这样,每次执行Order方法时,dispatcher发送“煮粥”指令,框架会自动执行CookCongeeCommand
命令。
除了上面以指令触发命令外,还可以以指令直接触发某个方法,这时需要dispatcher监听对应的方法和指令,比如:
public class customer
{
[Inject]
public IEventDispatcher dispatcher{get;set;}
void Order()
{
dispatcher.AddListener("煮粥",Think);
dispatcher.Dispatch("煮粥");//发送指令
}
void Think()
{
Debug.Log("不知道好不好喝");
}
}
这样,每次dispatcher发送“煮粥”指令,框架都会执行CookCongeeCommand
命令以及Think()
方法。
dispatcher有以下几种用法:
//添加监听
dispatcher.AddListener(AttackEvent.FIRE_MISSILE, onMissileFire);
//移除监听
dispatcher.RemoveListener(AttackEvent.FIRE_MISSILE, onMissileFire);
//更新监听
dispatcher.UpdateListener(true, AttackEvent.FIRE_MISSILE, onMissileFire);
dispatcher传递参数:
//不带参数方法
private void onMissileFire()
{}
//带参数的方法
private void onMissileFire(IEvent evt)
{
Vector3 direction = evt.data as Vector3;
}
//发送指令级参数
dispatcher.Dispatch(AttackEvent.FIRE_MISSILE,transform.position);
- 使用Signal发送指令
EventDispatcher可以发送多种不同的指令,但Signal是指责单一的,所以可能需要一个EventDispatcher实现的动能,就需要多个Signal才能实现。
Signal使用以下方式定义:
//无参数
Signal signal=new Signal();
//包含参数
Signal<int,int,string,...> signal=new Signal<int,int,string,...>();
Signal最多支持4个参数。(当参数多余4个时,可以将参数封装成类当作一个参数传递)
为了阅读方便,可以定义子类继承带参数的Signal,比如:
//定义子类
public class AddSignal:Signal<int,int>
{}
//声明实例
public AddSignal addSignal=new AddSignal();
那么,如何使用Signal呢?
- 引用strange.extensions.signal.impl
- 将上下文中默认的命令绑定替换为Signal,代码如下:
protected override void addCoreComponents()
{
base.addCoreComponents();
injectionBinder.Unbind<ICommandBinder>(); //解除默认绑定
injectionBinder.Bind<ICommandBinder>().To<SignalCommandBinder>().ToSingleton(); //添加新绑定
}
准备工作完成后,我们将上面使用EventDispatcher
的例子改为使用Signal方式。
- 1 声明信号子类
public calss CookCongeeSignal:Signal
{}
- 2 在上下文中添加绑定
commandBinder.Bind<CookCongeeSignal>().To<CookCongeeCommand>();
- 3 使用
public class customer
{
CookCongeeSignal cookSignal=new CookCongeeSignal ();
void Order()
{
cookSignal.Dispatch();.
}
}
这样,调用Order方法时,框架会通过cookSignal触发CookCongeeCommand命令。(注意:使用Signal时,命令类应继承自Command类,而不是EventCommand类)
同样,Signal也可以直接监听方法
public class customer
{
CookCongeeSignal cookSignal=new CookCongeeSignal ();
void Order()
{
cookSignal.AddListener(Think);
cookSignal.Dispatch();.
}
void Think()
{
Debug.Log("不知道好不好喝");
}
}
在某些情况下,可能需要Signal的单例:
injectBinder.Bind<CookCongeeSignal >().ToSingleton();
-
mediationBinder
- 中介绑定
这部分是作者专门为Unity开发的模块,在该部分,作者将传统MVCS中的V分为了view、mediator两部分。每个view都会对应一个mediator, mediationBinder
即是用来将view和mediator绑定的关键字。
比如:
//view类
public class RegisterView
{
void OnRegisterBto()
{
Debug.Log("注册按钮被点击了");
}
}
//mediator类
public class RegisterMediator
{
[Inject]
public RegisterView view{get;set;}
}
//在上下文中绑定两者
mediationBinder.Bind<RegisterView >().To<RegisterMediator>();
这样RegisterView和RegisterMediator就建立了对应关系。
原理明白了,来看看具体操作。
- 编辑view和mediator 类时需要引入
strange.extensions.mediation.impl
命名空间。 - view类需要继承自View,mediator需要继承自Mediator
即
using strange.extensions.mediation.impl;
public class RegisterView:View
{
}
//mediator类
public class RegisterMediator:Mediator
{
}
在Mediator中有几个特殊方法:PreRegister
,OnRegister
,OnRemove
-
PreRegister
- 在创建后立刻执行,执行顺序在注入之前 -
OnRegister
- 在所有注入完成后执行,一般用来做初始化 -
OnRemove
- 在view移除时执行
一个简单例子:
using strange.extensions.mediation.impl;
using UnityEngine;
public class RegisterView:View
{
public void Init()
{
//初始化
}
public void Clear()
{
//清除
}
}
//mediator类
public class RegisterMediator:Mediator
{
[Inject]
public RegisterView view{get;set;}
public override void OnRegister()
{
view.Init();
}
public override void OnRove()
{
view.Clear();
}
}