Reputation: 12005
I have service that performs requests to server:
export class ExportDictionaryApiService {
constructor(private http: HttpClient) {}
public perform(): Observable<any> {}
}
There is another class factory:
export class ExportFactory {
public static createConcreteExcel(type: string) {
switch (type) {
case EReferenciesTypes.DictionaryType:
return new ExportDictionary();
}
}
}
And concrete class that is returned by factory:
export class ExportDictionary implements IExport {
export(parameters: any) {
this.apiService
.perform().subscribe((response: IResponseDict) => {});
}
}
Using is:
ExportFactory.createConcreteExcel('full').export([...parameters]);
Problem is:
Concrete class should use concrete apiService
, and now there is no ready object apiService
inside class ExportDictionary
How to pass it in concrete class? I need return ready instance with all dependencies inside!
Certainly I can inject ready object in method:
ExportFactory.createConcreteExcel('full').export([...parameters], injectedApiService);
But I dont know injctedApiService
uNtil I dont create concrete Factory.
Also I can not create object inside:
export(parameters: any) {
new ExportDictionaryApiService()
.perform().subscribe((response: IResponseDict) => {});
}
Because ExportDictionaryApiService
requires dependency HttpClient
Upvotes: 3
Views: 97
Reputation: 19843
See this working example https://stackblitz.com/edit/angular-service-factory
p.s you can change the string to enum
Explanation
You need a factory as below
@Injectable()
export class ExportFactoryService {
constructor(
@Inject('Export') private services: Array<IExport>
) { }
create(type: string): IExport {
return this.services.find(s => s.getType() === type);
}
}
an interface for your service
export interface IExport {
getType(): string; // this can be enum as well
export(parameters: any):any;
}
and your service implementation, I implemented two services
@Injectable()
export class ExportDictionaryService implements IExport {
constructor() { }
getType(): string {
return 'dictionary';
}
export(parameters: any):any {
console.log('ExportDictionaryService.export')
}
}
and most important part, provide multiple services in app.module
providers: [
ExportFactoryService,
{ provide: 'Export', useClass: ExportDictionaryService, multi: true },
{ provide: 'Export', useClass: ExportJsonService, multi: true }
]
and this is how you get an instance of your service
constructor(private exportFactoryService: ExportFactoryService) {}
create() {
const exporter = this.exportFactoryService.create('dictionary');
exporter.export('full');
}
and this approach is Open-Closed, you can extent it by adding new services, and you don't need to modify existing codes, and there is not if/else, or switch/case statement , no static class, and it's unit testable, you can inject whatever is needed in each exporter services
Upvotes: 4