更多IoC的功能scope 定义IoC中可以定义scope,可支持singleton和prototype两种scope,默认情况下scope是singleton的。scope其实对应着常见的两种设计模式,即单例模式(singleton)和多例模式(prototype)。 singleton: { "name": "simple", "beans": [{ "id": "car", "func": "car", "scope": "singleton" }]} var car1 = bearcat.getBean('car');var car2 = bearcat.getBean('car');// car1 与 car2 是同一个实例对象 prototype: { "name": "simple", "beans": [{ "id": "car", "func": "car", "scope": "prototype" }]} var car1 = bearcat.getBean('car');var car2 = bearcat.getBean('car');// car1 与 car2 不是同一个实例对象 生命周期回调初始化与销毁操作在Node.js开发中是非常常见的。 初始化方法var Car = function() { this.num = 0;}Car.prototype.init = function() { console.log('init car...'); this.num = 1; return 'init car';}Car.prototype.run = function() { console.log('run car...'); return 'car ' + this.num;}module.exports = Car; car现在需要在实例化之后执行一个init方法来做些初始化的工作,那么在IoC中可以如下定义: { "name": "simple_init_method", "beans": [{ "id": "car", "func": "car", "scope": "prototype", "init": "init" }]} 销毁方法销毁方法在处理数据库链接等场景时非常有用。一个系统在shutdown的时候,平滑优雅的关闭就需要处理一些资源释放、完成未完成的任务等工作: var Car = function() {};Car.prototype.destroy = function() { console.log('destroy car...'); return 'destroy car';};Car.prototype.run = function() { console.log('run car...'); return 'car';};module.exports = Car; 当car结束生命的时候,需要执行一个destroy方法来释放资源,那么在IoC中可以如下定义: { "name": "simple_destroy_method", "beans": [{ "id": "car", "func": "car", "destroy": "destroy" }]} 异步初始化方法众所周知,Node.js中异步调用是非常平常的,比如初始化一个MySQL或者Redis的连接都是异步的,那么异步的初始化方法也就不可避免。而且在某些场景下,必须要求异步操作完成后,才能继续另外一个操作,这就要求保证两者之间的顺序性。在 Bearcat IoC中,你可以配置order和async来完成这样的初始化需求: var Car = function() { this.num = 0;}Car.prototype.init = function() { console.log('init car...'); this.num = 1;}Car.prototype.run = function() { console.log('run car...'); return 'car ' + this.num;}module.exports = Car; var Wheel = function() {}Wheel.prototype.init = function(cb) { console.log('init wheel...'); setTimeout(function() { console.log('asyncInit setTimeout'); cb(); }, 1000);}Wheel.prototype.run = function() { console.log('run wheel...'); return 'wheel';}module.exports = Wheel; 在这个简单的例子中,wheel有一个异步的初始化方法,它必须在car初始化之前调用,那么你就可以在context.json配置中配置wheel为async的,且order的值比car的要小,以表明wheel要在car之前初始化: { "name": "simple_async_init", "beans": [{ "id": "car", "func": "car", "init": "init", "order": 2 }, { "id": "wheel", "func": "wheel", "async": true, "init": "init", "order": 1 }]} IoC 实战随心所欲的单元测试在单元测试中,很多情况下需要构造一个对象的 mock 对象出来,然后被测试的对象调用这个mock对象来进行单元测试。但是在没有IoC之前,由于测试对象和mock原对象之间往往是紧密耦合的,那么要完成这样的操作,要么就是修改mock原对象的代码,要么就是修改测试对象的代码,但这样都不是最佳的实践。比如说一个基于express的web应用里面有一个userController,它依赖于userService: var userService = require('../service/user-service');exports.allUsers = function (req, res, next) { userService.getUsers(function (err, users) { if (err) { return next(err); } res.json(users); });}; 这时,如果想构造一个userService的mock对象mockUserService,并且在userController里面require进来进行测试的话,就需要修改userController里面的代码,比如这样子: //var userService = require('../service/user-service');var userService = require('../service/mock-user-service');exports.allUsers = function (req, res, next) { userService.getUsers(function (err, users) { if (err) { return next(err); } res.json(users); });}; 而通过IoC,这一切就变得非常的简单,无需修改代码即可完成。 在IoC容器管理下,依赖关系是通过对象给IoC容器的描述来完成的,因此,只需要修改context.json元数据配置,即可完成原始对象和mock对象之间的无缝切换: { "name": "simple_unit_test", "beans": [{ "id": "userController", "func": "userController", "props": [{ "name": "userService", "ref": "userService" }] }]} 改成如下所示的test-context.json即可。单元测试的时候,使用test-context.json来作为IoC容器的配置,既不影响开发,也可以完成测试工作,相当的便捷: { "name": "simple_unit_test", "beans": [{ "id": "userController", "func": "userController", "props": [{ "name": "userService", "ref": "mockUserService" }] }]} |