0.3.9 • Published 7 years ago
ts.di v0.3.9
Dependency Injection for TypeScript
tags: TS DI TypeScript Dependency-Injection
在学习Angular2的时候遇到了依赖注入,发现这个东西非常有用。于是便尝试自己实现了一下。
##API 主要API:
- @Injectable()
- @Singleton()
- @Inject()
- @Inject(()=>Type)
- Injector.get() 适用于不同场合的额外API:
- Injector.setSingleton()
##示例
@Injectable()
@Injectable()
class A {
}
@Injectable()
class B {
private val = '1234';
constructor(private a: A) {
}
getVal() {
return this.val;
}
setVal(newval) {
this.val = newval;
}
}
// 使用Injector.get(),不需要提供参数即可获取实例
let b = Injector.get(B);
let b2 = Injector.get(B);
// 测试:同一个Class可以被实例化多次,每个实例都是不同的对象。
let newVal = 'zzzz';
b.setVal(newVal);
assert.equal(b.getVal(), newVal);
assert.equal(b2.getVal(), '1234');
####@Inject() 和@Injectable()的用途一样,只不过这个是用于修饰属性的。
@Injectable()
class A {
@Inject()
b: ClassB;
}
####@Singleton
@Singleton()
class SingletonClass {
private val = '1234';
constructor(private a: A) {
}
get() {
return this.val;
}
set(newval) {
this.val = newval;
}
}
let b = Injector.get(SingletonClass);
let b2 = Injector.get(SingletonClass);
// 测试:被@Singleton()装饰的类,所有句柄都应该指向同一个对象
let newVal = 'zzzz';
b.set(newVal);
assert.equal(b.get(), newVal);
assert.equal(b2.get(), newVal);
####@Inject(()=>Type) @Injectable()无法处理A->B->A这样的循环依赖。 当A和B都是单例时,他们相互依赖的情况就很常见。而@Inject(()=>Type)就是为了处理这种依赖而诞生的。 使用@Inject(()=>Type)时,只要依赖循环中存在一个单例,整个循环中的所有实例便都可以被正确创建。
// singleton_class.ts
import {ClassA} from "./class_a"
@Singleton()
class SingletonClass{
}
// class_a.ts
import {SingletonClass} from "./singleton_class"
@Injectable()
class ClassA {
@Inject(()=>SingletonClass)
s: SingletonClass;
}
至于为什么要添加一个返回类型的函数作为参数才能解决循环依赖的问题,是因为TypeScript在两个文件相互包含的时候,必定有至少一个类的类型为undefine。添加一个参数其实是不得已为之的解决方案。
####Injector.setSingleton() 有时候,某些Singleton在实例化的时候需要特定的参数(string, number之类的参数),这些参数Injector没法帮你确定。 此时你需要自己手动创建一个Singleton实例让Injector使用它,这时你就该使用setSingleton。
let instance = new SomeClass(...);
Injector.setSingleton(SomeClass, instance);
// ... do someting
// 当你不再需要该实例的时候,可以删除该实例
Injector.setSingleton(SomeClass, undefined);
assert.equal(instance, Injector.get(SomeClass));// Injector.get会获取你所设置的实例
delete instance;
Injector.get(SomeClass); // Injector使用默认规则:尝试自动创建新实例或者引用已存在实例。
构建&测试
>npm install
>npm test
为什么是@Injectable()而不是@Injectable
装饰器本不需要添加一个括号的。就像这样:
@Injectable
class A{}
强制性添加括号是为了和Angular2的装饰器保持一致;也为了实现更好的扩展性。例如@Inject()可以传一个参数进去,解决循环依赖的问题。