如何使用Provider Factory的Injector

时间:2016-12-08 00:25:08

标签: angular dependency-injection

在我的Angular 2应用程序中,我有一个要求,我需要在运行时为给定的基本类型注册两种派生类型之一。我想出了这个:

在我的模块中,我使用了Provider Factory。 ApiService的构造函数需要角度Http服务和我自己的ConfigService,这就是deps属性的用途。

// imports omitted

let appContentBranchValue = 'myApp';

@NgModule({
    bootstrap: [AppComponent],
    declarations: [
        AppComponent
    ],
    imports: [ ... ],
    providers: [
        { provide: 'AppContentBranch', useValue: appContentBranchValue },
        { provide: ApiService,
          deps: [Http, ConfigService],
          useFactory: ApiServiceProviderFactory.create(appContentBranchValue) },
    ]
})
export class MyAccountModule { }

在我的TypeScript服务类中,在定义ApiService及其派生类型之前,我有这个Provider Factory实现。

我把实现放在这里主要是为了保持如何在模块之间选择ApiServiceMock和ApiServiceReal的逻辑。如果某个localStorage键存在且具有真值,则工厂将创建并返回ApiServiceMock,否则返回ApiServiceReal。

export class ApiServiceProviderFactory {
    public static create = (appContentBranch: string) => {
        let factory = (http: Http, configService: ConfigService): ApiService => {

            let flagKey = appContentBranch + '.mock.api';
            let flagValue = localStorage.getItem(flagKey);

            if (flagValue && JSON.parse(flagValue)) {
                return new ApiServiceMock(http, configService);
            } else {
                return new ApiServiceReal(http, configService);
            }
        };
        return factory;
    };
}

不是将Http和ConfigService传递给我的工厂函数,而是可以改为像这样传递Injector吗?

        let factory = (injector: InjectorOfSomeKind): ApiService => {

            let flagKey = appContentBranch + '.mock.api';
            let flagValue = localStorage.getItem(flagKey);

            if (flagValue && JSON.parse(flagValue)) {
                return injector.get(ApiServiceMock);
            } else {
                return injector.get(ApiServiceReal);
            }
        };
        return factory;
    };
}

如果我能做到这一点,那么可以完全避免如何调用构造函数的脏事。

可以这样做吗?问候,伊恩。

3 个答案:

答案 0 :(得分:0)

只需注入injector:Injector,然后使用injector.get(ApiService)

测试时可以使用

    TestBed.configureTestingModule({
        providers: [{provide: ApiService, useClass: ApiServiceMock}]   
    });

答案 1 :(得分:0)

我遇到了类似的需求,并且能够将dejector依赖性作为deps的一部分注入

const cookieServiceFactory = (platformId: object, injector: Injector) => {
return isPlatformBrowser(platformId) ? injector.get(BrowserCookieService) : injector.get(ServerCookieService);};

并注册如下

providers:[{provide:'cookieFactory', useFacory: cookieServiceFactory, deps:[PLATFORM_ID, Injector]}]

答案 2 :(得分:0)

如果我的理解正确,您想在运行时注入一个不同的ApiService实例,具体取决于所检索的本地存储键的值,该名称基于恒定值。


要根据您期望的标准注入正确的实现,请创建工厂函数并将所需的依赖项指定为函数参数。然后在模块定义中,在声明提供程序时使用deps属性,并将依赖项传递给函数参数。

就是这样!现在,您的工厂功能仅需要根据您的条件返回正确的实现。

MyAccountModule

const appContentBranch = 'myApp';

function apiServiceFactory(http: HttpClient, configService: ConfigService): ApiService {
  // retrieve key from LocalStorage
  const useMockApi = localStorage.getItem(`${appContentBranch}.mock.api`);

  // if key is present and its value is true
  if (useMockApi && JSON.parse(useMockApi)) {
    return new ApiServiceMock(http, configService);
  }
  // otherwise return real api
  return new ApiServiceReal(http, configService);
}

@NgModule({
  imports: [
    HttpClientModule,
  ]
  providers: [
    ConfigService,
    {
      provide: ApiService,
      useFactory: apiServiceFactory,
      deps: [HttpClient, ConfigService],
    },
  ]
})
export class MyAccountModule { }

ApiService

export abstract class ApiService {
  // define methods to implement
  // it needs to be an abstract class instead of an interface
  // so that it can be used as an injection token
}

ApiServiceMock

@Injectable()
export class ApiServiceMock implements ApiService {
  constructor(
    private http: HttpClient,
    private configService: ConfigService,
  ) { }
}

ApiServiceReal

@Injectable()
export class ApiServiceReal implements ApiService {
  constructor(
    private http: HttpClient,
    private configService: ConfigService,
  ) { }
}

Stackblitz示例:https://stackblitz.com/edit/angular-stackoverflow-41029733
更改useMockApiapp.module.ts属性的值,以测试在ApiService

的每个实现中声明的返回消息