通常认为好的面向对象的设计里,一个类只负责处理一件事情,为了遵守这个规则,几乎所有的对象都必须合作才能完成它们的职责,但是那些合作的对象来自哪里?典型的,没有依赖注入,你只能实例化合作的对象在你的组件里,这样就会产生一个紧的藕合在你的对象之间.久而久之会让你的应用难于维护并且你的组件很难进行单元测试.此时依赖注入就应运而生.当你想使用一个框架或者一个容器来注入那些合作的对象至那些需要这些对象的对象里时,)这是一种非常强大的模式,你能开发你想要的那些对象并且独立地测试它们并且将它们捆绑到一起来构建你的应用.SPRING框架就是一个很常见的依赖注入框架在JAVA开发的世界里。
我将使用SPRING框架的一个子集,SPRING-MVC 作为一个例子. 在SPRING-MVC中你能控制那些从客户端进入的请求对象,在这种情况下,假设一个WEB浏览器,现在普遍的WEB应用,在系统的后端都有一个数据库或一个数据仓库包含了一些信息能够被取出并且显示给用户.假设用户进入了一个按作者搜索的书籍列表,在最简单的情况下,控制器对象要接受一个请求,从请求参数里取出作者名称,交给BookService对象来处理这个名称并且期望它返回一个书籍标题的清单列表,接着在响用户的请求时返回这个标题清单,SPRING框架能够设置BookService对象进入到控制器中(通过配置XML文件或者注释声明,当然这个在另一篇文章里讲),事实上你的Bookservice对象实现在JAVA接口,这就意味着它能够改变服务对象的实现让控制器对象不可见.这是一件好事情.和参数一样,并且返回类型都不用改变.控制对象也不用关心service对象如何处理它自己的事情,但是在FLEX开里又能够做些什么呢?
接口式的依赖注入是非常强大的,你有一系列对象要互相依赖来完成他们的工作,并且你希望有一个特别实现的对象能够取代那种如果一旦改变就要求改变里面的所有依赖对象的状况,而对象仅仅只是关心特别指定的接口.这样改变实现就能做到XX并且测试也更加容易,好,来猜下,AS3支持同样的接口构造并且能写出松散的代码如此容易吗?
一种方式你可以像在JAVA里面一样利用同样方式的接口:
定义你的接口,在AS3中接口应该是这样的:
package com.example { public interface Controller { public function search(searchParams:Object,callback:Function=null):void } }
定义一个类实现接口:
package com.example { public class HttpController implements Controller{ private var _httpService:HTTPService=new HTTPService(); public function search(searchParams:Object,callback:Function=null):void { details omitted for clarity } } }在上面的例子中 , 你有一个控制器接口和一个实现 HttpController 将被用来执行 searchs 方法来与你应用中的后台进行通信 是用 Flex 的 HttpService 对象来完成发送搜索请求并处理响应工作的 . 你可以看到 对象是在 类中被实例化的 所以为什么不注入 类呢 ? 这里指出一个接口你可以改变它的实现来适合于你的应用 在这种情况下 如果你需要另一种搜索结构 你可以简单写一个新的实现或者修改已存在的那个即可
public class SearchPanel extends Panel{ private _searchController:Controller; public function search(text:String):void { this._searchController.search(text,this.callBackFunction); } public function set searchController(searchController:Controller):void { this._searchController = searchController; } public function get searchController():Conroller { return this._searchController; } }
上面的例子中的关键点儿是实例变量 Controller类型的_searchController和它的getter和setter方法名称除了”_”之外名称是相同的,下面来看一下取名为SearchPanelView.mxml的MXML文件它代表组件的可视化属性。
<?xml version="1.0" encoding="utf-8"?> <SearchPanel xmlns="bbejeck.example.*" xmlns:comp="bbejeck.example.*" xmlns:mx="http://www.adobe.com/2006/mxml"> <comp:HttpController id="searchController" /> </SearchPanel>
在上面的MXML文件中,这儿有几个关键点:
1.在<comp:HttpController id="searchController" />这一行,定义了controller组件被SearchPanel类使用,注意定义的类名是HttpController,当这种类型的变量_searchController实例变量只要是一个Controller类型,它不做被实现的任何事情.
2.id属性匹配SearchPanel类中的set和get方法的函数名称
3.当SearchPanelView.mxml文件被Flex应用加载时,"HttpController"对象实例化后,与SearchPanel类中的Id属性相匹配的setter方法会被调用,注入到你的Controller类的实现到SearchPanel类中
4.当你需要改变你的搜索功能时,你可以不用改变HttpController对象,或者定义一个新的实现并且修改SearchPanelView.mxml文件,总之你的SearchPanel不需要做任何改动
你已经看到了在FLEX中怎样进行依赖注入,在FLEX应用中将会把那些你定义到MXML中的ID与对象中同名的setter方法注入到你的组件中,我们实质上已经自由地得到了一个基本的依赖注入容器在FLEX中。我们得出一些结论:
当构建一个应用时,替代构建应用自身的关注点,你关注那些在构建项中所需要的个别的组件并且这些组件需要做哪些工作.你可以结束大量的在构建项目中需要的一些实现回调或服务对象的组件的准备工作,代码重用是非常高并且可以减少很多时间来构建一个新的项目。
单元测试是非常简单的,现在如果你的组件是基于接口合作(交互)的,当你在测试这些组件时你可以手工调用相应的setter方法并且提供模拟对象实现正确地接口,但是提供了需要的行为供你测试。