robotlegs 全面解读(一)

[size=large]robotlegs [b] 全面解读(一)[/b][/size]
—基于元数据的依赖注入

简介:这片教程将和大家一起学习robotlegs的最大特性—依赖注入。通过本篇文章你将会了解,swifsuspender框架是如果基于元数据进行依赖注入的。本文章将结合实例,以最通俗的语言给大家讲解。

首先我们先来理解几个词汇:

其实有时候我们不需要知道这些专业词汇的概念性定义,我只需要知道他在哪里、起了什么作用就行了。

依赖:例如在A类里边,你需要用到b对象的某属性,那么你需要在A类里边做b的引用;
 
Class A
{
public var b:B;
}


这个时候我们就说A就依赖于b,或说b是A的依赖。


注入:还是刚才的A、b为例,刚才我们在A类声明了b但是并没有赋值。这个时候我们在C类里声明a实例,并对其变量赋值;

Class C
{
public var a:A = new A();
public var b:B=new B();
public function C():void
{
a. b= b; //====
}
}


a. b= b; 这个赋值过程我们就叫注入。

元数据:我想这个东西大家应该也都用过,比如我们在Main类前边加的 【swf 】,它可以用来指定舞台大小及帧频。这种方式其实就在给Main类添加元数据,这个[swf]我们叫它元数据标签。除【swf】之外flash内置的标签还有,用来导入外边资源的【Embed】、添加事件处理函数接口的【Event】等,在我们给类添加了这些元数据标签之后, flashplayer运行的时候就会做相应处理。
以上是flash内置的元数据标签,那么我们能不能自定义标签呢,答案是肯定的。其实我们可以在自己的类里边随意添加自定义的标签,它是不会影响类的正常运行。看下例:

//我们建立这样一个类:
//然后在其属性前添加元数据

package {
public class MyClass extends Object{

[MyMatedata(name="value1",name2="value2")]
public var a:String;
public function MyClass(){
super();
}
public function getA():void{
trace("dd");
}
}
}


其中[MyMatedata(name="value1",name2="value2")]就是我们随便加的一个标签。那这个标签加在这会有什么用呢?

我们看一个as3的公共方法describeType(value:*):XML 通过此方法我们可以得到对象的XML表示。

package {
public class Main extends Sprite
{
public function Main (){
super();
var myXml:XML= describeType(new MyClass())

trace(myXml); //打印XML对象
}
}
}


//我们将得到日志:
1 <type name="MyClass" base="Object" isDynamic="false" isFinal="false" isStatic="false">
<extendsClass type="Object"/>
<variable name="a" type="String">
<metadata name="MyMatedata">---------------------------------->自定义元数据
<arg key="name" value="ha"/>
<arg key="name2" value="haha2"/>
</metadata>
<metadata name="__go_to_definition_help">
<arg key="pos" value="108"/>
</metadata>
</variable>
<method name="getA" declaredBy="MyClass" returnType="void">
<metadata name="__go_to_definition_help">
<arg key="pos" value="189"/>
</metadata>
</method>
<metadata name="__go_to_ctor_definition_help">
<arg key="pos" value="137"/>
</metadata>
<metadata name="__go_to_definition_help">
<arg key="pos" value="26"/>
</metadata>
</type>


Variable:为属性标签
Method:为方法标签
Metadata:为元数据标签

我们可以在<variable name="a" type="String">标签里边看到我们添加的元数据:

<metadata name="MyMatedata">
<arg key="name" value="ha"/>
<arg key="name2" value="haha2"/>
</metadata>




到这里大家应该明白了,其实元数据就是在我们的类里边加一些标记。这样我们就可以根据这些标记对这个对象做一些操作,比如注入。通过解读对象的元数据来进行的注入就是基于元数据的依赖注入了。

下边是我做的一个例子,比较简单,它和swifsuspender框架一样都实现了基于元数据的依
赖注入。

//Injector 为注入器,我只实现了属性注入,较框架里的注入器要简单,易于大家理解。
package org
{
import flash.utils.Dictionary;
import flash.utils.describeType;
import flash.utils.getQualifiedClassName;

public class Injector
{
/**
*储存所有映射的字典,key为[class+#+name],value为Class或Class的实例
*/
private var m_mappings:Dictionary;
/**
* 储存注入描述的字典
*/
private var m_injectteeDescriptions:Dictionary;

public function Injector(xmlConfig : XML = null)
{
m_mappings=new Dictionary(true);
m_injectteeDescriptions=new Dictionary(true);
}

/**
* 将类映射到一个对象,这样在请求[class+name]的时候,就会返回指定的对象
* @param whenAskedFor - 请求的类
* @param useValue - 请求类时返回的对象
* @named named - 注入名,对类进一步区分,[whenAskedFor的全名+'#'+named]是映射的key
*
*/
public function mapValue(whenAskedFor : Class, useValue : Object, named : String = "") : void
{
var requestName:String=getQualifiedClassName(whenAskedFor);//获得类全面
m_mappings[requestName+"#"+named]=useValue;
}

/**
* 向目标注入
* @param target
*/
public function injectInto(target:Object):void
{
var classZ:Class=target.constructor; //得到目标类
var injectionPoints:Vector.<PropertyInjectionPoint>=m_injectteeDescriptions[classZ];

if(!injectionPoints)
{
injectionPoints=getInjectionPoints(classZ);
}

for(var i:int=0;i<injectionPoints.length;i++)
{
var injectionPoint:PropertyInjectionPoint=injectionPoints[i];
var response:Object=m_mappings[injectionPoint._propertyType+"#"+injectionPoint._propertyName];

if(response)
{
target[injectionPoint._injectionName]=response
}
}
}

/**
*读取一个类的属性注入点
* @param clazz 读取的类
* @return Vector.<PropertyInjectionPoint> 所有属性注入点列表
*
*/
private function getInjectionPoints(clazz:Class):Vector.<PropertyInjectionPoint>
{
var description:XML=describeType(clazz); //获取类的XML描述信息。
var injectionPoints:Vector.<PropertyInjectionPoint>=new Vector.<PropertyInjectionPoint>();

var injectionPoint:PropertyInjectionPoint;// 声明注入点
var node:XML;

//对于variable结点中metadata的name是Inject的节点,
for each (node in description.factory.variable.metadata.(@name == 'Inject'))
{
injectionPoint = new PropertyInjectionPoint(node);//注入点为PropertyInjectionPoint对象,即属性注入点对象
injectionPoints.push(injectionPoint);//在注入点队列中添加改注入点
}

m_injectteeDescriptions[clazz]=injectionPoints;
return injectionPoints;
}
}
}

/**
* 【包外类】属性注入点描述类
* */
final class PropertyInjectionPoint
{
public var _propertyName : String; //注入的属性名称
public var _propertyType : String; //注入点类型
public var _injectionName : String;//注入名

public function PropertyInjectionPoint(node:XML)
{
_propertyName=node.parent().@type.toString();
_propertyName=node.parent().@name.toString();
_injectionName=node.arg.attribute("value").toString();
}
}



//被注入的类AClass
package org
{
public class AClass
{
[Inject]
public var b:BClass;
public function AClass()
{
}

public function handler():void
{
trace(b);
}
}
}
//被映射的类BClass
package org
{
public class BClass
{
public var property:String="";

public function BClass()
{
}
}
}


//文档类

package
{
import flash.display.Sprite;

import org.AClass;
import org.BClass;
import org.Injector;

public class Main extends Sprite
{
private var injector:Injector=new Injector()
public function Main()
{
var b:BClass=new BClass();
b.property="property from BClass";
injector.mapValue(BClass,b);

var a:AClass=new AClass();
injector.injectInto(a);
a.handler();
}
}
}

//声明:此实例只供参考,如有疏漏,欢迎大家批评指出。


作者:王闯
email :wangchuang1113@163.com;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值