如何在基于组件的提供程序中即时交替服务 class 实施?

How to alternate service class implementation on-the-fly in component based provider?

我还是新来的 Angular。目前,我在我们的一个组件中有两个基于一个抽象 class 的 REST 服务实现。就像这样scenario,唯一不同的是我在组件级别注入服务:

@Component({
  selector: 'this-is-tag',
  template: htmlStr,
  providers: [{ provide: RESTToken, useClass: FirstRESTService }],
  ...

问题是,我可以根据特定配置在运行时切换实现吗?或者,我应该使用不同的方法来解决这个问题吗?

编辑:

看来我需要使用接口,而不是这里的抽象 class。

解决方案是使用 useFactory 而不是 UseClass,更改您的代码,如下例所示: 首先,创建一个工厂 class 并决定 DI 逻辑:

export function myFactory() {
  if(myRule){
       return new FirstRESTService();
    }
  return new  SecondRESTService();
}

然后将您的组件代码更改为:

@Component({
  selector: 'this-is-tag',
  template: htmlStr,
  providers: [{ provide: RESTToken, useFactory: myFactory}],

有时候会有一种情况,你想给工厂添加一些依赖,因为你需要它来决定returnserviceA还是serviceB。 为了满足这一点,我们可以像这样使用 deps 属性:

export function myFactory(obj:MyDependencyClass) {
  if(obj.HasMyRule){
       return new FirstRESTService();
    }
  return new  SecondRESTService();
}

此外,在您的组件中:

@Component({
  selector: 'this-is-tag',
  template: htmlStr,
  providers: [{ provide: RESTToken, useFactory: myFactory}],
  deps: [MyDependencyClass]

但不要忘记在 app.module.ts.

中包含 MyDependencyClass

所以,我最终使用接口,而不是抽象 class 来解决这个问题。而且,当我尝试对我的两项服务使用基 class 时,继承方法失败,例如 this question.

这是我的工作解决方案,包括 JIT 和 AOT 编译:

@Component({
  selector: 'invoice-list',
  templateUrl: './invoice-list.component.html',
  providers: [{ provide: RESTToken, useClass: InvoiceRESTService }],
  ...

组件中实际使用的服务:

@Injectable()
export class InvoiceRESTService {

    public invoiceType: InvoiceType;

    constructor(
        private _visma: VismaRESTService,
        private _fortnox: FortnoxRESTService
    ) {}

    public get instance(): RESTServiceInterface {

        if (this.invoiceType === InvoiceType.Visma) {
            return this._visma;
        } else if (this.invoiceType === InvoiceType.Fortnox) {
            return this._fortnox;
        } else {
            console.log('Please set the invoice type.');
        }
    }

}

界面本身:

export interface RESTServiceInterface {

  getExportDataFunctionURL(): string;

  // So far, only for Visma
  getAuthUrl?(): string;

  getButtonTitlle(): string;

  synchData(instanceUid: string, code?: string): Observable<Object>;

  updateInvoice(payload: any): Observable<Object>;

  // Loading messages
  getWaitingMessage(): string;

  getSuccessMessage(): string;

  getErrorMessage(code: VismaErrorCode | FortnoxErrorCode | BKErrorCode): string;

}

实现接口的服务:

@Injectable({
  providedIn: 'root'
})

export class FortnoxRESTService implements RESTServiceInterface {
   ...
   ...
   ...
}


@Injectable({
    providedIn: 'root'
})

export class VismaRESTService implements RESTServiceInterface {
   ...
   ...
   ...
}