如何在基于组件的提供程序中即时交替服务 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 {
...
...
...
}
我还是新来的 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 {
...
...
...
}