Как использовать @Inject и получить экземпляр службы не в конструкторе?

#angular #dependency-injection

#angular #внедрение зависимостей

Вопрос:

У меня есть универсальный класс, который использует http внутри него:

 export abstract class GenericCrudService<T> {
  constructor(protected http: HttpService, protected resourse: Resourse) {}

  private entities: T[] = [];
  entitiesChanged$: Subject<T[]> = new Subject();

  getAllEntities() {
    this.http.get<T>(environment.endpoint   this.resourse).subscribe((res) => {
      this.entities = res;
      this.entitiesChanged$.next(this.entities);
    });
  }

  createEntity(entity: T) {
    return this.http
      .post(environment.endpoint   this.resourse, entity)
      .subscribe((_) => {
        this.entities.push(entity);
        this.entitiesChanged$.next(this.entities);
      });
  }
  deleteEntity(id: string) {
    return this.http
      .delete(environment.endpoint   this.resourse, id)
      .subscribe((res: any) => {
        this.entities = this.entities.filter((e: any) => e._id !== res.deleted);
        this.entitiesChanged$.next(this.entities);
      });
  }

  updateEntity(id: string, newEntity: T) {
    return this.http
      .put(environment.endpoint   this.resourse, id, newEntity)
      .subscribe((res: any) => {
        const updatedIndex = this.entities.findIndex(
          (e: any) => e._id === res.updated
        );
        this.entities[updatedIndex] = newEntity;
        this.entitiesChanged$.next(this.entities);
      });
  }

  getLatestEntities() {
    return this.entitiesChanged$.asObservable();
  }
}
 

также есть эта служба, которая расширяет этот класс:

 @Injectable({
  providedIn: "root",
})
export class ExerciseService extends GenericCrudService<IExercise> {
  constructor(http: HttpService) {
    super(http, Resourse.exercise);
  }
}
 

Я подумал, что было бы лучше не вводить http-клиент в службу упражнений, поскольку он ему не нужен, и создавать его только в общем, выполнив что-то вроде:

@Ввести (HTTP_TOKEN?) http: HTTPService и использовать this.http везде в службе. Мой вопрос в том, возможно ли это и рекомендуется ли это, и если да, то как я могу получить токен для внедрения HTTPService или как я могу его создать, если он не существует?

Комментарии:

1. JFYI: resourse = Resourse.exercise; строка избыточна, так как это уже сделано в parent . в вашей версии логика «назначения» просто дублируется.

2. это было по ошибке

3. @Andrey итак, каково ваше предложение по рефакторингу в этом коде?

Ответ №1:

существует только один «элегантный» способ внедрить что-либо в Angular, и это способ конструктора. Другой способ — ввести инжектор в конструктор и Injector.get(токен) в любой момент времени выполнения.

 myService = this.injector.get(MyService);
constructor(private injector: Injector) {}

 

в вашем коде это было бы

 export abstract class GenericCrudService<T> {
  protected http = this.injector.get(HttpService);
  constructor(protected injector: Injector, protected resourse: Resourse) {}
...
}
....
export class ExerciseService extends GenericCrudService<IExercise> {
  constructor(injector: Injector) {
    super(injector, Resourse.exercise);
  }
}
 

тогда в любых потомках вы передадите инжектор только родительскому, и parent может вводить все, что захочет, с помощью этого инжектора

Комментарии:

1. так что лучше делать это так, как я, чем @Inject(HTTP_TOKEN?) http: HTTPService в службе? Что, если я расширил более двух уровней? Как вы думаете, правильно ли передавать зависимости таким образом?

2. вы могли бы использовать angular DI, если обсуждение касалось компонентов, потому что у них есть инжекторы уровня компонентов. это было бы возможно @Component({... providers: [provide: Resource, useValue: Resource.excercise]}) class MyClass {} ; но жаль, что службы не могут этого сделать. Если у вас есть планы многоуровневого наследования, то я бы использовал Injector в конструкторе, а затем внедрил все, что нужно, в parent. Это лучше, если вы хотите добавить зависимости на одном из «родительских» уровней. никаких других обновлений, кроме 1 класса, не потребуется.

3. Не могли бы вы показать мне, как это реализовано в моем коде, пожалуйста?

4. Спасибо за вашу помощь 👍