Angular 와 유사 한 의존 주입 을 간단하게 실현 합 니 다.
Angular 는 자신의 의존 주입 프레임 워 크 가 있 습 니 다. 이 프레임 워 크 를 떠 나 면 Angular 응용 프로그램 을 구축 할 수 없습니다.
다음은 Angular 의존 주입 과 같은 간단 한 (100 줄 정도 코드 만 있 음) 방식 을 소개 합 니 다. 먼저 예 를 들 어 보 겠 습 니 다.
// a.service.ts
@Injectable()
export class AService {
constructor() {
}
public doSomething() {
console.log('this is AService::doSomething');
}
}
// b.service.ts
@Injectable()
export class BService {
constructor(private readonly a: AService) {
}
public doSomething() {
this.a.doSomething();
console.log('this is BService::doSomething');
}
}
// some.module.ts
@Module({
providers: [
AService,
BService,
],
})
export class SomeModule {
}
위의 예 에서 우 리 는 두 개
Service
를 만 들 었 는데 그 중에서 BService
는 AService
에 의존 했다. 그러면 BService
구조 함수 에서 그 의존 을 설명 할 수 있다. 우 리 는 AService
의 인 스 턴 스 를 BService
의 개인 읽 기 전용 변수 a
에 자동 으로 주입 하 는 방법 이 필요 하 다. 다음 에 실현 절 차 를 소개 한다.우선 우 리 는
Typescript
의 장식 기 (또는 주석) 를 지원 하도록 설정 해 야 합 니 다. 다음은 제 설정 파일 입 니 다.{
"compilerOptions": {
"lib": [
"dom",
"es2015"
],
"target": "es5",
"module": "commonjs",
"outDir": "./dist",
"strict": true,
"esModuleInterop": true,
"experimentalDecorators": true,
"emitDecoratorMetadata": true
}
}
그 중에서
Javascript
는 ES 장식 기 에 실험 지원 을 사용 하 는 것 을 나타 낸다. experimentalDecorators
는 소스 코드 에서 장식 성명 을 위해 유형의 메타 데 이 터 를 만 들 었 다 고 밝 혔 다. 이 두 가 지 를 설정 한 후에 야 우 리 는 emitDecoratorMetadata
장식 기 를 사용 할 수 있다. 그 다음 에 우 리 는 의존 Typescript
을 설치 하여 메타 데 이 터 를 읽 고 설정 해 야 한다.@ Injectable 의 실현
reflect-metadata
은 장식 기구 로 표지 가 장식 되 어 있 는 유형 은 @Injectable
이 고 그의 성명 방식 은 다음 과 같다.export function Injectable(): ClassDecorator {
return (target) => {
};
}
우 리 는 이 장식 기 에서 아무것도 하지 않 고 그 는 표지 의 역할 만 한다.
@ Module 의 실현
Provider
은 장식 기구 로 표지 가 장식 되 어 있 는 유형 은 @Module
이 고 그의 성명 방식 은 다음 과 같다.const DI_IMPORTS_SYMBOL = Symbol('di:imports')
const DI_PROVIDERS_SYMBOL = Symbol('di:providers')
export function Module(options: { imports?: Array, providers?: Array }): ClassDecorator {
return (target) => {
Reflect.defineMetadata(DI_IMPORTS_SYMBOL, new Set(options.imports || []), target);
Reflect.defineMetadata(DI_PROVIDERS_SYMBOL, new Set(options.providers || []), target);
}
}
우 리 는
Module
역할 영역 에서 설명 한 Set
과 그 가 도입 한 다른 모듈 을 저장 하기 위해 Module
를 사용 합 니 다.Factory 의 실현
우리 가 달성 하고 자 하 는 목적 은 사용 할 때
Providers
를 통 해 Factory.create(SomeModule)
의 인 스 턴 스 를 얻 은 다음 Module
인 스 턴 스 를 통 해 Module
를 얻 는 것 이다. 예 를 들 어 Provider
이 때 출력 해 야 한다.Factory.create(SomeModule).get(BService).doSomething();
// this is AService::doSomething
// this is BService::doSomething
Talk is cheap. Show me the code:
export namespace Factory {
export function create(module: Type) {
const imports: Set = Reflect.getMetadata(DI_IMPORTS_SYMBOL, module);
const providers: Set = Reflect.getMetadata(DI_PROVIDERS_SYMBOL, module);
const providersMap = new Map();
const importModules = Array.from(imports).map((importModule) => {
let moduleInstance: ModuleInstance = moduleInstances.get(importModule);
if(!moduleInstance) {
moduleInstance = create(importModule);
moduleInstances.set(importModule, moduleInstance);
}
return moduleInstance;
});
const moduleInstance = new ModuleInstance(importModules, providersMap);
providers.forEach(provider => {
createProvider(provider, providers, moduleInstance);
});
return moduleInstance;
}
function createProvider(provider: any, providers: Set, moduleInstance: ModuleInstance) {
let providerInstance = moduleInstance.providers.get(provider);
if(providerInstance) {
return providerInstance;
}
const deps: Array = Reflect.getMetadata('design:paramtypes', provider);
if(!deps) {
throw new Error(`No provider named ${ provider.name }, do yout add @Injectable() to this provider?`);
}
const args = deps.map(dep => {
let depInstance = moduleInstance.providers.get(dep);
if(!depInstance) {
if(providers.has(dep)) {
depInstance = createProvider(dep, providers, moduleInstance);
} else {
moduleInstance.imports.some(imp => {
depInstance = createProvider(dep, new Set(), imp);
return !!depInstance;
});
}
}
if(!depInstance) {
throw new Error(`can not found provider ${ dep.name }`);
}
return depInstance;
});
providerInstance = new provider(...args);
moduleInstance.providers.set(provider, providerInstance);
return providerInstance;
}
export class ModuleInstance {
constructor(
public imports: Array,
public providers: Map) {
}
get(provider: Type) {
let instance: T = this.providers.get(provider);
if(!instance) {
this.imports.some(imp => {
instance = imp.get(provider);
return !!instance;
});
}
if(!instance) {
throw new Error(`No provider named: ${ provider.name }`);
}
return instance;
}
}
}
이상 은 전체 의존 주입 의 실현 입 니 다. 관심 이 있 는 친 구 는 제 Github 에서 소스 코드 를 볼 수 있 습 니 다. 핵심 파일 은
Factory.create(SomeModule).get(BService).doSomething()
입 니 다. 주 소 는?https://github.com/hungtcs/li...
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
스프링에서 주입에 의존하는 세 가지 방식 분석스프링은 의존 주입 사상을 제기했다. 즉, 의존류는 프로그래머가 실례화하지 않는다는 것이다.스프링 용기를 통해 new 실례를 지정하고 이 대상이 필요한 클래스에 실례를 주입합니다.주입에 의존하는 또 다른 표현은'반전...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.