Rob*_*Foo 13 javascript dependency-injection
用一个例子可以更好地说明这个问题.我将使用Javascript(实际上是Coffeescript的语法),但仅仅因为Javascript只是另一个LISP,对吧?
所以,假设我正在编写一个(显然)执行ajax请求的Web应用程序.我实现了一个函数来处理:
ajaxRequest = (url, params, callback) ->
# implementation goes here
Run Code Online (Sandbox Code Playgroud)
现在,假设我有一个从服务器获取数据的网格.我的代码中的某处我必须做这样的事情:
userGrid.onMustFetch = ->
ajaxRequest '/fetch/users', { surname: 'MacGyver' }, (data) ->
# fill grid with data
Run Code Online (Sandbox Code Playgroud)
究竟是什么问题?如果我想测试onMustFetch的实现,我将无法这样做,因为在onMustFetch中,正在调用依赖项,并且测试环境无法控制依赖项.
为了解决这个问题,我将依赖项注入到我想要测试的函数中.这意味着将onMustFetch更改为:
userGrid.onMustFetch = (ajaxRequest) ->
ajaxRequest '/fetch/users', { surname: 'MacGyver' }, (data) ->
# fill grid with data
Run Code Online (Sandbox Code Playgroud)
现在测试代码可以将ajaxRequest的模拟传递给onMustFetch并成功测试行为.
Wunderbar,对吧?错误!现在我有一个第二个问题,不必权实例绑定的问题ajaxRequest到正确的实例onMustFetch.
在像Java这样的语言中,我可以使用依赖注入框架为我做这个,我的代码看起来像这样:
class UserGrid {
private AjaxService ajaxService;
@Inject
public UserGrid(AjaxService ajaxService) {
this.ajaxService = ajaxService;
}
public void onMustFetch() {
HashMap<String, String> params = new HashMap<String, String>();
params.put("surname", "MacGyver");
ajaxService.request("/fetch/users", params, new AjaxCallback(data) {
// fill grid with data
});
}
}
Run Code Online (Sandbox Code Playgroud)
令人毛骨悚然,我知道......但实际上DI框架完成了所有的布线,所以至少问题的这一部分更容易.
现在回到我们的网络应用程序和Javascript.即使我成功地设法总是使用正确的ajaxRequest引用调用onMustFetch(毕竟在这种情况下并不那么难),必须有一种更简单的方法.当我的代码增长时,依赖关系会增加.我可以想象传递一个ajaxRequest的引用,但是当我有一个securityService,一个browserService,一个eventBusService等等时呢?
现在真正的问题是:像语言这样的lisp如何解决管理依赖关系的问题?(在我看来,依赖关系必须继续在整个应用程序中传递,但我确信必须有更好的方法...)
这通常使用闭合/卷曲来完成.您将依赖项作为参数传递.在JS中你可以这样做:
buildUserGrid = function(dependency){
return {
onMustFetch = function(){
depenency.doSomething();
},
doSomethingElse = function(){
dependency.doSomethingElse();
}
}
}
var userGrid = buildUserGrid(ajaxRequest);
userGrid.onMustFetch();
Run Code Online (Sandbox Code Playgroud)
在 Javascript 中,我不知道为什么不能使用类似于任何 OO 语言的技术。一个非常基本的 JS 实现(抱歉,我不知道 Coffescript)
// expects a function
var UserGrid = function(ajaxService) {
this.dependencies = ["ajaxService"];
// will be overwritten by the DI service, but can also be
// assigned manually as in java
this.ajaxService = ajaxService;
};
UserGrid.prototype.onMustFetch=function() {
var callback = function() { ... }
this.ajaxService('/fetch/users',{ surname: 'MacGyver' }, callback);
};
var diController = {
create: function(constr) {
var obj = new constr();
// just look at obj.dependencies to see what should be assigned, and map
// the implemenations as properties of obj. this could be
// as simple as a switch or a direct mapping of names to object types
// ... assign implementations to obj
return obj;
}
};
Run Code Online (Sandbox Code Playgroud)
创造:
var userGrid = diController.create(UserGrid);
Run Code Online (Sandbox Code Playgroud)
所以diController和你的java依赖注入器做同样的事情。在java中,它可以使用反射来找出需要什么类型的对象。Javascript 中不需要做太多反映,因此创建一个约定来告诉系统需要什么。在本例中,我使用了一个名为“依赖项”的数组,但您可以使用您喜欢的任何构造。
| 归档时间: |
|
| 查看次数: |
2989 次 |
| 最近记录: |