StrangeloC内部运行机制

StrangeIoC的设计和RobotLegs一致,所以我的解析会对照RobotLegs来看。

整个框架使用的是MVCS的模式,关于MVCS模式大家可以点这里进行查看,这里就不谈了,既然StrangeIoC称为依赖注入框架,我们就直接谈这个框架的注入实现。

中介类的生命周期

为啥不先说注入呢?因为自动创建和销毁中介类是我认为这个框架设计得最精彩的地方。

大家一定很好奇,当我们挂载了View脚本的GameObject添加到场景时,对应的中介类就会生成并绑定到该GameObject之上,同时中介类会通过注入获取到View的实例,而当GameObject被销毁时中介类也会被移除,下面我们一起看看这里面的玄机吧。

自动实例化中介类

首先所有的视图脚本都必须继承自View类,所以我们要揭开自动实例化的秘密就必须先从这个类入手,我们先看看View类的Awake和Start方法:

 1 /// A MonoBehaviour Awake handler.
 2 /// The View will attempt to connect to the Context at this moment.
 3 protected virtual void Awake ()
 4 {
 5     if (!registeredWithContext)
 6         bubbleToContext(this, true, false);
 7 }
 8 
 9 /// A MonoBehaviour Start handler
10 /// If the View is not yet registered with the Context, it will 
11 /// attempt to connect again at this moment.
12 protected virtual void Start ()
13 {
14     if (!registeredWithContext)
15         bubbleToContext(this, true, true);
16 }

注意:这里的方法并不是默认的void Start之类的写法,而是作为保护的虚函数进行定义的,这样可以使我们的子类进行对应的扩展。

下面我们看看这段代码的意思是啥:

两个方法一致,这里判断的意思是:如果还没有在Context中进行注册,则先通过冒泡的方式找到Context(所谓的冒泡就是递归寻找父级对象,如果找到包含了ContextView脚本的父级对象,则认为是找到了Context,这也是为啥所有需要注入功能的GameObject都必须作为子孙对象被放在包含了ContextView脚本的GameObject中的原因。),并告诉它添加了一个视图对象。

技术分享

(为了省事,干脆就把所有的GameObject都放在包含ContextView脚本的GameRoot下吧。)

接下来框架会从我们在Context中注册的信息里找到这个视图对应的中介类类型,并创建它添加到GameObject中,代码在MediationBinder的mapView中,如下:

 1 /// Creates and registers one or more Mediators for a specific View instance.
 2 /// Takes a specific View instance and a binding and, if a binding is found for that type, creates and registers a Mediator.
 3 virtual protected void mapView(IView view, IMediationBinding binding)
 4 {
 5     Type viewType = view.GetType();
 6 
 7     if (bindings.ContainsKey(viewType))
 8     {
 9         object[] values = binding.value as object[];
10         int aa = values.Length;
11         for (int a = 0; a < aa; a++)
12         {
13             MonoBehaviour mono = view as MonoBehaviour;
14             Type mediatorType = values [a] as Type;
15             if (mediatorType == viewType)
16             {
17                 throw new MediationException(viewType + "mapped to itself. The result would be a stack overflow.", MediationExceptionType.MEDIATOR_VIEW_STACK_OVERFLOW);
18             }
19             MonoBehaviour mediator = mono.gameObject.AddComponent(mediatorType) as MonoBehaviour;
20             if (mediator is IMediator)
21                 ((IMediator)mediator).PreRegister ();
22             injectionBinder.Bind (viewType).ToValue (view).ToInject(false);
23             injectionBinder.injector.Inject (mediator);
24             injectionBinder.Unbind(viewType);
25             if (mediator is IMediator)
26                 ((IMediator)mediator).OnRegister ();
27         }
28     }
29 }

我们可以在19行看到中介类被添加了。

RobotLegs的做法

AS3中一个显示对象添加到舞台时会触发对应的事件,RobotLegs就是通过监听这个事件,在这个事件中创建中介类的。而StrangeIoC使用的是Awake和Start事件,也可以理解为添加到场景。

自动销毁中介类

销毁我们倒回来看看View类中的OnDestroy方法:

1 /// A MonoBehaviour OnDestroy handler
2 /// The View will inform the Context that it is about to be
3 /// destroyed.
4 protected virtual void OnDestroy ()
5 {
6     bubbleToContext(this, false, false);
7 }

逻辑与Awake和Start一致,不同的是传递的参数不一致,这里也是通过冒泡找到Context并告诉它我移除了一个视图对象,框架会找到这个中介类并调用其OnRemove方法,代码在MediationBinder的unmapView中,如下:

 1 /// Removes a mediator when its view is destroyed
 2 virtual protected void unmapView(IView view, IMediationBinding binding)
 3 {
 4     Type viewType = view.GetType();
 5 
 6     if (bindings.ContainsKey(viewType))
 7     {
 8         object[] values = binding.value as object[];
 9         int aa = values.Length;
10         for (int a = 0; a < aa; a++)
11         {
12             Type mediatorType = values[a] as Type;
13             MonoBehaviour mono = view as MonoBehaviour;
14             IMediator mediator = mono.GetComponent(mediatorType) as IMediator;
15             if (mediator != null)
16             {
17                 mediator.OnRemove();
18             }
19         }
20     }
21 }

下面我们来看看注入是怎么实现的。

RobotLegs的做法

同样AS3中一个显示对象从舞台移除时也会触发对应的事件,通过监听这个事件就可以移除对应的中介类了。

注入是如何实现的?

刚开始使用这个框架的童鞋肯定会惊叹于为什么写了[Inject]以后就可以自动获取对应的对象的实例,这种技术称为注入,其实原理很简单,就是使用了Attribute和反射两种特性而已。

我们还是以中介类为例子来看,中介类被创建后会进行注入,其中最重要的就是注入对应的视图脚本对象。代码在MediationBinder的mapView中,如下:

1 injectionBinder.Bind (viewType).ToValue (view).ToInject(false);
2 injectionBinder.injector.Inject (mediator);
3 injectionBinder.Unbind(viewType);

这3行的解析如下:

  1. 记录添加的视图脚本对象,绑定到视图类型上;
  2. 对中介类进行注入,当发现有[Inject]的标签的属性时,同时类型为视图类型,则将上一步记录的视图脚本实例赋值给他;
  3. 注入完毕,取消记录的视图脚本对象。

那么注入的核心逻辑呢?我们来看看Injector类的Inject方法:

 1 public object Inject(object target, bool attemptConstructorInjection)
 2 {
 3     failIf(binder == null, "Attempt to inject into Injector without a Binder", InjectionExceptionType.NO_BINDER);
 4     failIf(reflector == null, "Attempt to inject without a reflector", InjectionExceptionType.NO_REFLECTOR);
 5     failIf(target == null, "Attempt to inject into null instance", InjectionExceptionType.NULL_TARGET);
 6 
 7     //Some things can‘t be injected into. Bail out.
 8     Type t = target.GetType ();
 9     if (t.IsPrimitive || t == typeof(Decimal) || t == typeof(string))
10     {
11         return target;
12     }
13 
14     IReflectedClass reflection = reflector.Get (t);
15 
16     if (attemptConstructorInjection)
17     {
18         target = performConstructorInjection(target, reflection);
19     }
20     performSetterInjection(target, reflection);
21     postInject(target, reflection);
22     return target;
23 }

最开始的3行是做异常判断的;

下面有一个判断,如果是原生类型、数字或字符串就不处理了;

接下来会取出要被注入的对象的所有反射信息;

再接下来就是进行注入,解析如下:

  1. 如果要对构造函数的参数进行注入则进行构造函数参数的注入;
  2. 对属性进行注入;
  3. 对标记了[PostConstruct]标签的方法进行调用;
  4. 返回目标对象,此时注入已经完成。

注入实现解说

好吧,还是没搞懂注入究竟是怎么实现的?下面就大概说一下思路,不看代码了:

答案就是:使用反射获取类的所有信息,而Attribute可以为类、方法、属性等添加标记,这些标记也是可以由反射获得的,那么框架就可以知道什么属性是需要注入的了,只要这个属性被[Inject]标记即可,框架找到这些属性,通过类型判断按Context中注册的规则(比如是否为单例类型等)将对象的实例赋值给该属性。

一些其他的知识点

ToSingleton

作为单例注入,其作用是保证每次通过[Inject]标签获取的对象都是同一个对象,即只有一个实例,该实例在第一次获取时进行创建。

如果不作为单例注入,则每次通过[Inject]标签获取的对象都是新创建的实例,哪怕是同一个类写了2个[Inject]同一类型的对象,获取的实例也是两个不同的对象(虽然类型相同)。

dispatcher和IEvent

整个框架内部进行消息传递都靠这个类实现;

但是整个框架中其实存在两种dispatcher,一种负责在MVCS之间进行消息传递(注意这里的V指的是中介类),还有一种是负责视图类发送消息给中介类的dispatcher;

两种dispatcher不通用,即一种发送的消息另一种不会收到。

Once和InSequence

Once表示立即执行命令,并且命令执行完毕后就移除该命令的映射关系;

InSequence表示按照注册的前后顺序来调用命令;

InParallel表示平行执行命令,即不关系命令的前后调用顺序。

框架学习笔记:深度解析StrangeIoC内部运行机制

原文:http://www.cnblogs.com/hammerc/p/4763037.html

http://www.360doc.com/content/16/0330/16/7014874_546568514.shtml


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
前言 unity的框架,除了各大公司自己内部使用的,开源并好用的实际并不是很多,我会慢慢挖掘,依次写出自己的一点见解,错误的地方,望各路大神指正。 一、基本概念 控制反转(Inversion of Control,英文缩写为IOC),我的理解就是,原本A类要获取B类的对象,需要你在A类中自己New一个对象,那么是由A来获取并控制B的对象,IOC就是把对象获取的这个过程交给容器和依赖注入来处理,A类并不知道B的对象是哪里来的,对B对象的控制,由自己变成了其他类,官方一点的概念可以百度,这个还是蛮多的。 二、StrangeIOC基础类型 实际要理解一个框架的类型,还是要自己看源码,这里我只说一下几个重要类型的作用,这个看源码的时候有个印象,也方便理解,而且说这部分的帖子也很多,我就不再赘述了。 1.Context 上下文组件定义程序边界,也就是可以把一个程序定义成多上下文,让代码更加模块化 它提供了程序入口,也算是框架中耦合度最高的地方 2.Binder和Binding 这两个类是这个框架最重要的组成部分 Binding存储了对象的绑定关系,而Binder存储了Binding的对象 3.View和Mediator MVCS中的View层,View只用于显示,也就是View只负责管理UI,Mediator负责界面逻辑,事件响应等 4.Model MVCS中的Model层,负责数据部分 5.Command MVCS中的Control层,负责执行逻辑代码 6.Service MVCS中的Service层,负责与第三方交互,这个Service我理解的,并不是一定指代服务器,也可以是其他的软件,什么都可以,它就是我们程序对外的接口 7.Dispatcher 派发器是框架内通信主线的其中一种,用来派发消息,触发命令,从而进一步解耦 8.Signal 信号是框架内另外一种通信主线,它采用强类型,来绑定信号和命令之间的关系,实现消息响应的触发 9.ReflectionBinder 反射部分,通过binding来获取类的信息,存储在ReflectedClass中 10.injector 注入器,通过反射获取的信息,来实例化请求的对象 --------------------- 作者:蓝天小僧 来源:CSDN 原文:https://blog.csdn.net/zcaixzy5211314/article/details/80876228 版权声明:本文为博主原创文章,转载请附上博文链接!

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值