分享

DI学习

 昵称10338395 2012-07-06
 
 一,依赖注入:
 1,此时,ServiceUser不能作为组件来发布,应为在不同的使用环境下,ServiceProvider的实现是千差万别的(例如数据存储,有SQL Server,File,Internet等).
为了将ServiceUser所在的单元作为组件发布使用,必须满足以下的要求:
1)将ServiceUser与具体的ServiceProverder实现的依赖解耦(编译时依赖,new ServiceProver_Imp()).
2)在运行时为ServiceUser提供正确的ServiceProvider的实现(File?).
总之,将ServiceUser与ServiceProvider之间的依赖,由编译时,推迟到运行时来动态决定.即在运行时"注入"这种依赖.即DI(依赖注入).
2,ServiceUser可看做框架(需要对外发布,被使用),ServiceProvider可看做插件(不同环境下是有差别的).
3,DI:在编译时,使用接口,在运行时再将具体的实现类型进行绑定.从而实现服务使用者(框架)和服务提供者(插件)的松耦合.
二,
 
1,加入一个容器(Assembler)来完成将ServiceUser框架单独发布所需的要求.
2,构造器DI:指的是ServiceUser的构造器,也就是在构造ServiceUser时,才把具体的ServiceProvider_IMP传给它.
       Class ServiceUser{  IServiceProvider sp;        ServiceUser(IServiceProver sp){ this.sp = sp;}   }
       private MutablePicoContainer configureContainer() {
               MutablePicoContainer pico = new DefaultPicoContainer();
             //下面就是把ServiceProvider和ServiceUser都放入容器的过程,以后就由容器来提供ServiceUser的已完成依赖注入实例,
             //其中用到的实例参数和类型参数一般是从配置档中读取的,这里是个简单的写法。
             Parameter[] finderParams =  {new ConstantParameter("movies1.txt")};
             pico.registerComponentImplementation(IServiceProvider.classServiceProvider.class, finderParams);
             pico.registerComponentImplementation(ServiceUser.class);
            //至此,容器里面装入了两个类型,其中没给出构造参数的那一个(ServiceUser)将依靠其在构造器中定义的传入参数类型,在容器中
            //进行查找,找到一个类型匹配项即可进行构造初始化。
            return pico;
       }
   1)依赖被延迟到容器的构造过程中.
   2)容器本身(具体是其构造过程)对ServiceProvider和ServiceUser都有依赖.
   3)所以,ServiceUser,ServiceProvider,容器,三者没有任何依赖关系.所有的依赖关系,所有的变化,都被封装到了容器构造中.实际项目中,可以使用配置文件来将变化排斥到编译期之外.
   4)容器含有一个类似GetInstance(Type t)的方法,在该方法中,容器调用ServiceUser的构造器,而其参数是在容器添加ServiceProvider时指定的.
3,设值DI:其与2的差别在于在获取对象实例(GetInstance)的时候,前者是通过反射得到待创建类型的构造器信息,然后根据构造器传入参数的类型在容器中进行查找,并构造出合适的实例;而后者是通过反射得到待创建类型的所有属性,然后根据属性的类型在容器中查找相应类型的实例。这种方式比较利用使用XML配置的方式来实现,所以Spring等使用.
4,接口DI:首先在接口中定义需要注入的信息,然后ServiceUser实现该接口.最后,容器调用接口定义的注入方法来完成注入.
三,Service Locator:
 
1,
 
 
2,模式背后的基本思想是:有一个对象(即服务定位器)知道如何获得一个应用程序所需的所有服务.
3,其与DI的区别是ServiceUser需要显式的调用Service Locator来获取具体的ServiceProvider IMP.而DI是由容器隐式的实现这一切的.
4,由于ServiceUser和ServiceLoader的依赖性,从而降低了模块的独立性.所以IOC框架都使用了DI.
5,但是Service Loader实现简单,所以当开发不复杂时,可以使用SL.
四,DI VS SL :
1,首先,两者都提供了将ServiceUser和ServiceProvider IMP 两者解耦的能力.
2,两者的区别是,SP IMP以什么方式提供给ServiceUser.在SL中,ServiceUser直接向SL发送消息来请求具体的SP IMP;在DI中,ServiceUser不用再显式的请求,而SP IMP会自动出现.
3,控制反转是框架的特征,这增加了框架代码的理解难度,并增加了调试的难度.
4,两者的决定取决于对SL的依赖是否会给你带来麻烦.
5,DI模式可以帮助你看清组件之间的依赖关系:你只需观察依赖注入的机制(例如构造函数),就可以掌握整个依赖关系。而使用SL模式时,你就必须在源代码中到处搜索对服务定位器的调用 .
6,首先,取决于ServiceUser的性质,如果有多个ServiceUser要使用同一服务,那么可以使用SL.但是如果要将ServiceUser所在的项目作为组件发布给别人使用,因为别人的SL是不可预测的,很可能带来不兼容等等问题,所以可以使用DI.
7,另一方面,DI中,由于容器和SP IMP之间没有依赖关系,所以,除了配置文件的信息,SP IMP无法获取更多的Assembler的信息.
8,部分人认为DI简化了测试,因为可以简单地在真实的SP IMP和伪组件之间的切换.但是,如果良好的实现应该能够轻松地替换掉SL.也就是说,良好地架构应该支持简单地使用一个伪组件来替换一个真实组件来测试.
9,所以,如果SP IMP要脱离自己的控制,在另外一个APP中使用,那么就不应该对SL进行任何的假设.
 五,构造函数DI VS 设值DI.
1,根源:应该在哪里填充字段的值?构造函数还是设值方法?
2,构造函数的一个好处是隐藏不可变的字段,只要在构造函数内将其设置,然后不提供Setter即可.
3,但是问题:1)如果参数过多,2)参数多是无法描述信息的简单类型.3)对象含有多个构造函数,且存在继承关系.
六,代码配置 VS 配置文件.
1,简单的应用程序,直接使用代码进行配置.
2,当配置文件变得复杂时,使用一种编程语言来编写配置文件.
七,分离配置和使用.
1,关键在于:服务的配置应该与使用分开。实际上,这是一个基本的设计原则——分离接口与实现。在面向对象程序里,我们在一个地方用条件逻辑来决定具体实例化哪一个类,以后的条件分支都由多态来实现,而不是继续重复前面的条件逻辑,这就是分离接口与实现的原则.

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多