读一读

因为是有关Command和Service的事件,所以将事件枚举命名为

public enum SMCubeEvent {
    GetPositionComplete
}

先看Service层吧

//接口
using strange.extensions.dispatcher.eventdispatcher.api;

public interface IPositionServise  {

    [Inject]
    IEventDispatcher dispatcher { get; set; }

    void GetPosition();
}
//实现
using strange.extensions.context.api;
using strange.extensions.dispatcher.eventdispatcher.api;

public class LinePositionServise : IPositionServise
{
    [Inject]
    public CubePositionModel DataModel { get; set; }

    [Inject]//局部的分发器
    public IEventDispatcher dispatcher { get; set; }

    public void GetPosition()
    {
        //假装是远程获取的数据
        Vector3 pos = new Vector3(Random.Range(0, 2), Random.Range(0, 2), Random.Range(0, 2));

        //保存数据到Model
        DataModel.pos = pos;

        //获取到后通知Command层回调
        dispatcher.Dispatch(SMCubeEvent.GetPositionComplete,pos);
    }
}

然后是Command层

using strange.extensions.command.impl;
using strange.extensions.dispatcher.eventdispatcher.api;

public class CubeInitCommand : EventCommand {

    [Inject]//注入服务层,用来调用事先准备好的接口
    public IPositionServise PositionServise { get; set; }

	public override void Execute ()
	{
        Retain();//保持Command不被销毁,因为服务层获取数据一般都不是立刻的
        PositionServise.dispatcher.AddListener(SMCubeEvent.GetPositionComplete, OnComplete);
        //通过服务层获取数据
        PositionServise.GetPosition();
	}

    private void OnComplete(IEvent evt) {
        dispatcher.RemoveListener(SMCubeEvent.GetPositionComplete, OnComplete);
        //发送命令给Mediator,初始化位置
        dispatcher.Dispatch(MCCubeEvent.InitPositionComplete, (Vector3)evt.data);

        Release();//释放掉,放置内存泄漏
    }
}

总结:这个的交互和View-Mediator有点相像。在Command中获得Service的注入,直接调用接口来交互它,Command中通过注入的Service的局部dispatcher来监听它请求数据的完成回调,当Service层发出相应的请求完成事件,Command中的回调自然被触发。不同的是,因为Service层一般是用来和网络交互的,也就是说它提供的接口是有延迟性的,而Command是完成就会被销毁的,所以要用Retain()来保持Coammand不被销毁,事件完成后在手动销毁Release()。


因为是有关Mediator和Command的事件,所以将事件枚举命名为

public enum MCCubeEvent  {
    UpdateCunePos,
    UpdateCunePosComplete
}

先是Mediator层

using UnityEngine;
using strange.extensions.mediation.impl;
using strange.extensions.dispatcher.eventdispatcher.api;
using strange.extensions.context.api;

public class CubeViewMediator : EventMediator {

	[Inject]
	public CubeView cubeView{ get; set;}

	public override void OnRegister ()
	{
        //监听Command处理完成的回调
        dispatcher.AddListener(MCCubeEvent.UpdateCunePosComplete, OnUpdatePosComplete);
        cubeView.dispatcher.AddListener(VMCubeEvent.UpdatePosition, OnUpdatePos);
    }

	public override void OnRemove ()
	{
        cubeView.dispatcher.RemoveListener(VMCubeEvent.UpdatePosition, OnUpdatePos);
        dispatcher.RemoveListener(MCCubeEvent.UpdateCunePosComplete, OnUpdatePosComplete);
    }

    private void OnUpdatePos(IEvent evt) {
            //发送命令给Commamd,事先会在Context下绑定,直接调用Command的Execute()方法
        dispatcher.Dispatch(MCCubeEvent.UpdateCunePos,(int)evt.data);
    }

    private void OnUpdatePosComplete(IEvent evt) {
        cubeView.UpdatePosition((Vector3)evt.data);
    }
}

然后是Command层

using UnityEngine;
using strange.extensions.command.impl;

public class CubeUpdateCommand : EventCommand {

    [Inject]
    public CubePositionModel DataModel { get; set; }

    public override void Execute()
    {
        Vector3 newPos = DataModel.pos;
        newPos.x += Random.Range(-2f, 2f);
        DataModel.pos = newPos;

        //处理完后,回调给Mediator,Mediator事先已经监听好了
        dispatcher.Dispatch(MCCubeEvent.UpdateCunePosComplete,newPos);
    }
}

下面是绑定

commandBinder.Bind(MCCubeEvent.UpdateCunePos).To<CubeUpdateCommand>();

总结:两者都是通过全局的dispatcher发送事件的。Mediator通过发送事先在绑定处绑定好了命令的事件来通知Command处理,Command通过发送Mediator层事先绑定好的回调事件来通知Mediator。


因为是View和Mediator的交互,所以我将事件枚举命名为

public enum VMCubeEvent  {
    UpdatePosition,
}

新建CubeView

using UnityEngine;
using strange.extensions.mediation.impl;
using strange.extensions.dispatcher.eventdispatcher.api;
public class CubeView : View {

    [Inject]//使用局部的派发器
    public IEventDispatcher dispatcher { get; set; }
    
    //提供接口
	public void UpdatePosition(Vector3 pos){
		this.transform.position = pos;
	}

    private void OnMouseDown()
    {
        //Cube被点击后,发送命令通知Mediator
        dispatcher.Dispatch(VMCubeEvent.UpdatePosition,Random.Range(1,10));
    }
}

对应的Mediator

using UnityEngine;
using strange.extensions.mediation.impl;
using strange.extensions.dispatcher.eventdispatcher.api;
using strange.extensions.context.api;

public class CubeViewMediator : EventMediator {

	[Inject]//注入View,直接调用View接口交互
	public CubeView cubeView{ get; set;}

	public override void OnRegister ()
	{
	//监听View层发出的命令
        cubeView.dispatcher.AddListener(VMCubeEvent.UpdatePosition, OnUpdatePos);
    }

	public override void OnRemove ()
	{
        cubeView.dispatcher.RemoveListener(VMCubeEvent.UpdatePosition, OnUpdatePos);
    }

    private void OnUpdatePos(IEvent evt) {
        //发送命令去Command层做逻辑计算等
        //evt.data  View传过来的数据
        //当命令有回应时,直接调用View接口传递给View
        //cubeView.UpdatePosition((Vector3)evt.data);
    }
}

总结:View用来和用户交互,感知事件的发生,然后通过局部的dispatcher派发命令通知Mediator层,Mediator事先通过这个局部的dispatcher监听好事件的回调,触发这个回调(处理),处理完成后,通过View引用直接访问提供好的接口更新交互。


1.创建空物体Root,创建RootContextView挂载上去,用来实例化Context。

//RootContextView.cs文件
using strange.extensions.context.impl;
using UnityEngine;

public class RootContextView : ContextView {

    void Awake() {
		//创建Context
		this.context = new DemoContext (this);
    }

}

2.创建DemoContext类,用来绑定

using UnityEngine;
using strange.extensions.context.impl;//MVCSContext 
using strange.extensions.context.api;//ContextEvent.START

public class DemoContext : MVCSContext {

	public DemoContext(MonoBehaviour view):base(view){}

	protected override void mapBindings ()
	{
		//Binding Todo
		//绑定启动命令,此方法完成后,就会自动分发ContextEvent.START命令
		commandBinder.Bind (ContextEvent.START).To<StartCommand> ().Once();
	}

}

3.创建StartCommand类,作为启动命令。

using UnityEngine;
using strange.extensions.command.impl;

public class StartCommand : Command {

	public override void Execute ()
	{
		Debug.Log ("Hello World!");
	}
}

4.解说一下,创建RootContextView继承自ContextView(MonoBehaviour的子类),挂载到场景中,自动实例化调用Awake()方法,实例化DemoContext类,DemoContext类继承自MVCSContext,里面重写了mapBindings()方法在Context创建时自动调用,用于绑定关系,最后绑定启动命令到StartCommand,在绑定结束后就会调用这个事件,调用StartCommand的Execute()方法,游戏的起点。


class-flow.png

StrangeIoc是一个基于MVCS的小型框架。M指的是模型,用于访问数据层,保存取出来的数据等。V指的是视图,就是我们看到的东西,一般会以组件的形式挂载到GameObject上。C指的是Controller,利用命令Command负责和Service、Model、Mediator的交互。S指的是服务层,用户与存储服务器交互,请求、更新、保存数据。

  1. Root继承自contextView用来当做足见挂载到物体上,主要作用来实例化Context。

  2. Context用来绑定各个层次东西的关系等,绑定一个叫ContextEvent.START的命令,自动触发,这是开始。

  3. View挂在了物体上,会自动实例化,实例化后会自动创建Mediator中间层并调用OnRegister()方法,发送命令请求S或M获取初始化数据,绑定一些监听等,如数据更新等。

  4. S层会将数据保存到M层。

  5. M和S接受到命令,取出数据后,在发送命令回Mediator中间层。