敲碎时间的人的个人专栏
上一篇

Injector框架理解(八)

广告
选中文字可对指定文章内容进行评论啦,→和←可快速切换按钮,绿色背景文字可以点击查看评论额。
大纲

上一节我们学习了didi框架如何使用子加载器加载子模块的一些知识,还有包括初始化一些基本组件,今天我们继续学习相关的知识,还是从一个例子开始。

const { Injector } = require('didi');
const { expect } = require('chai');
const injector = new Injector([
{
  __exports__: [ 'foo', 'bar' ],
  'foo': [
	'factory',
	function(bar) {
	  return {
		bar: bar
	  };
	}
  ],
  'bar': [
	'factory',
	function(internal) {
	  return {
		internal: internal
	  };
	}
  ],
  'internal': [
	'factory',
	function() {
	  return {};
	}
  ]
}
]);
const foo = injector.get('foo');
const bar = injector.get('bar');
const childInjector = injector.createChild([], [ 'foo', 'bar' ]);
const fooFromChild = childInjector.get('foo');
const barFromChild = childInjector.get('bar');

expect(fooFromChild).to.not.equal(foo);
expect(barFromChild).to.not.equal(bar);
expect(fooFromChild.bar).to.equal(barFromChild);
console.log('private injector');

输出如下:

从以上例子可以看出,从父加载器获取的组件和子加载器获取的相同的组件是不同的组件,但是它们的各自的加载器中获取的依赖项都是同一个组件。

下面我们再看看Injector作用域的问题,我们用下面的例子来说明问题:

const { Injector } = require('didi');
const { expect } = require('chai');
function Foo() {}
Foo.$scope = [ 'request' ];

function createBar() {
    return {};
}
createBar.$scope = [ 'session' ];

const injector = new Injector([
{
  'foo': [ 'type', Foo ],
  'bar': [ 'factory', createBar ]
}
]);
const foo = injector.get('foo');
const bar = injector.get('bar');

const sessionInjector = injector.createChild([], [ 'session' ]);
expect(sessionInjector.get('foo')).to.equal(foo);
expect(sessionInjector.get('bar')).to.not.equal(bar);

const requestInjector = injector.createChild([], [ 'request' ]);

expect(requestInjector.get('foo')).to.not.equal(foo);
expect(requestInjector.get('bar')).to.equal(bar);
console.log('injector scope');

大家注意,这里的作用域加载器有点奇怪,首先我们定义了两个组件foobar,它们各自的作用域分别是requestsession,可以看出的如果用session加载器来加载的话,那么同一个session加载器下的所有request作用域的组件都是一样(与父模块获取的组件相比)的,而同一个session加载器下的所有session作用域组件是不一样的。

相反的是,如果使用resuest加载器来加载的话,那么request作用域的组件每次都不一样,而session作用域的组件都是一样的。

下面我们看看组件的定义替换,用下面的例子来说明这个功能如何使用:

const { Injector } = require('didi');
const { expect } = require('chai');
class Foo {
  constructor(bar1, baz1) {
     this.bar = bar1;
     this.baz = baz1;
  }
}

function createBlub(foo1) {
  return foo1;
}

const base = /** @type ModuleDeclaration */ ({
  foo: [ 'type', [ 'bar', 'baz', Foo ] ],
  blub: [ 'factory', [ 'foo', createBlub ] ],
  baz: [ 'value', 'baz-value' ],
  abc: [ 'value', 'abc-value' ]
});

const extension = /** @type ModuleDeclaration */ ({
  foo: [ 'type', [ 'baz', 'abc', Foo ] ]
});

const injector = new Injector([ base, extension ]);
const expectedFoo = {
  bar: 'baz-value',
  baz: 'abc-value'
};

expect(injector.get('foo')).to.deep.equal(expectedFoo);
expect(injector.get('blub')).to.deep.equal(expectedFoo);
console.log('replace definition via override module');

输出如下:

从以上的代码我们看出,foo组件本来是依赖于barbaz这三个组件的,现在我定义了一个扩展模块之后,这个foo组件依赖于bazabc组件。也就是说,如果父组件的以前有一个实现方法的话,那么我想扩展这个组件,可以通过定义一个扩展模块来修改父组件的实现,从而让后来的版本兼容以前的版本。

从以上还可以看出的是,这种实现方式真正实现了对扩展开放而对具体的实现隔离。

版权声明:著作权归作者所有。