Robotlegs中的注入是由注入器Injector实现,先来看看Robotlegs中哪些地方存在注入器Injector。
首先Context里面有Injector,CommandMap、MediatorMap和ViewMap里面也有Injector。
Context自身内部除了有一个Injector单例之外还有CommandMap、MediatorMap、ViewMap这些单例,这些对象内部具有Injector。Robotlegs框架内部存在Injector的类基本上就是这4个,当然除了Context内部的commandMap、mediatorMap、viewMap单例之外你也可以手动创建新的CommandMap、MediatorMap、ViewMap,本文不讨论这种情况,我们在此只分析Robotlegs内置结构的4种Injector和它们的注入机制,后面提到的CommandMap、MediatorMap、ViewMap皆是指Context.commandMap、Context.mediatorMap和Context.viewMap。
Context,CommandMap,MediatorMap,ViewMap内部都有Injector,但它们是不同的。CommandMap.injector和MediatorMap.injector是Context.injector的子注入器,它们都继承了Context.injector的注入规则,同时又拥有各自的注入规则。而ViewMap.injector使用的就是Context.injector,也就是说ViewMap和Context的注入器是同一个。
Robotlegs区别与其他mvc框架的特色是运用了命令模式和中介模式规范了注入机制的使用,从而使整个应用程序框架结构更清晰高效易于维护。下面我们具体来分析一下这些注入机制。
Context相关的注入机制
Context中的Injector就是注入器的一般用法,Context在初始化的时候内部的添加了下面这些注入规则:
injector.mapValue(IReflector, reflector);
injector.mapValue(IInjector, injector);
injector.mapValue(IEventDispatcher, eventDispatcher);
injector.mapValue(DisplayObjectContainer, contextView);
injector.mapValue(ICommandMap, commandMap);
injector.mapValue(IMediatorMap, mediatorMap);
injector.mapValue(IViewMap, viewMap);
injector.mapClass(IEventMap, EventMap);
被Context.Injector(或者子注入器)注入过的类内部都可以接收这些注入规则。注意这里的EventMap不是对象实例,每个IEventMap请求都会得到一个新的EventMap对象。此外,经过ViewMap映射的显示对象也可以接收这些注入规则,本文ViewMap相关的注入机制中会介绍。
CommandMap相关的注入机制
CommandMap内部的Injector是Context.Injector的子注入器。调用CommandMap.mapEvent方法时需传入(eventType:String, commandClass:Class, eventClass:Class = null)这些参数,CommandMap为总线eventDispatcher添加名为eventType的事件侦听。 当总线eventDispatcher派发名为eventType的事件时CommandMap执行了如下代码:
injector.mapValue(Event, event);//这里Event是flash.events.Event 或者是eventClass类型,event是总线eventDispatcher派发的事件。 var command:Object = injector.instantiate(commandClass); command.execute();
总线eventDispatcher接收到事件时Robotlegs会创建commandClass对象实例,同时把event注入到了commandClass,如果commandClass内部需要接收这个注入只要加入如下代码:
[Inject] public var event:Event; //也可以把Event换成eventDispatcher派发的具体事件类型eventClass。
前面说过CommandMap.Injector是Context.Injector的子注入器,所以CommandMap.Injector把自身的注入规则注入到commandClass的同时也会把Context.Injector的注入规则注入进commandClass。事实上commandClass的基类Command已经为我们定义了下面这些注入点,我们在commandClass内部可以直接使用这些注入。
[Inject] public var contextView:DisplayObjectContainer; [Inject] public var commandMap:ICommandMap; [Inject] public var eventDispatcher:IEventDispatcher; [Inject] public var injector:IInjector; [Inject] public var mediatorMap:IMediatorMap;
MediatorMap相关的注入机制
MediatorMap内部的Injector是Context.Injector的子注入器。调用MediatorMap.mapView方法时需传入(viewClass:*, mediatorClass:Class, injectViewAs:* = null)这些参数,MediatorMap为contextView添加Event.ADDED_TO_STAGE事件,viewClasss实例为显示对象且必须为contextView的子显示对象。当viewComponent显示对象创建并添加到Stage的时候MediatorMap执行了如下代码:
var mediator:IMediator; injector.mapValue(viewClass, viewComponent); mediator = injector.instantiate(mediatorClass); mediator.onRegister();
所以Robotlegs在创建mediatorClass对象实例的同时把viewComponent注入到了mediatorClass,如果mediatorClass内部需要接收这个注入只要加入如下代码:
[Inject] public var view:viewComponent;
在mediatorClass的onRegister方法内部可以访问到注入的view。 另外要注意的是一个mediator可以对应多个view,MediatorMap.mapView方法有injectViewAs这个参数,它可以是一个viewClass组成的数组,如果是这种情况injector会为每一个viewClass都创建注入规则,这样在mediatorClass内部可以接收多个viewClass注入。 当injectViewAs参数非空的时候会忽略viewClass参数。
同样,前面说过MediatorMap.Injector是Context.Injector的子注入器,所以MediatorMap.Injector把自身的注入规则注入到mediatorClass的同时也会把Context.Injector的注入规则注入进mediatorClass。事实上mediatorClass的基类Mediator已经为我们定义了下面这些注入点,我们在mediatorClass内部可以直接使用这些注入。
[Inject] public var contextView:DisplayObjectContainer; [Inject] public var mediatorMap:IMediatorMap;
ViewMap相关的注入机制
ViewMap可以添加显示对象(DisplayObject的子对象),经过ViewMap.mapType添加的显示对象第一次被放置到舞台的时候会被注入Context.injector的注入规则,在这些对象内部可以添加注入点来接收Context.injector的注入。当显示对象添加到舞台时ViewMap执行了如下代码:
injector.injectInto(target);
这里的injector就是Context.injector,target是被ViewMap.mapType添加过的显示对象。target可以接收的注入规则可以参考上面的Context相关的注入机制。 此外ViewMap还有一个ViewMap.mapPackage方法用来添加类名前缀,如果被放置到舞台的显示对象的类名符合这些前缀同样也会被注入Context.injector的注入规则。
KevinChu
2014-6-11