Zastosowanie InjectionToken do wstrzykiwania serwisów opartych na wspólnym interfejsie

przez | 24 listopada 2024

InjectionToken to mechanizm w Angularze, który pozwala na wstrzykiwanie zależności bez konieczności polegania na konkretnych klasach. Jest to szczególnie przydatne w przypadku, gdy chcemy korzystać z interfejsu jako abstrakcji dla komponentów lub serwisów. W tym artykule rozwiniemy temat poruszony w InjectionToken – podstawy oraz pokażemy, jak wykorzystać InjectionToken, aby zaimplementować interfejs klasy w dwóch serwisach.. Skupimy się na wstrzykiwaniu serwisów do komponentu, bazując na interfejsie zdefiniowanym w InjectionToken.

Definiowanie interfejsu i tokenu

Rozpocznijmy od zdefiniowania interfejsu, który będzie wspólny dla obu komponentów:

export interface TitleInterface {
  getTitle(): string;
}

Teraz możemy utworzyć InjectionToken, który będzie reprezentował nasz interfejs:

import { InjectionToken } from '@angular/core';
import { TitleInterface } from './title.interface';

export const TITLE_INTERFACE_TOKEN = new InjectionToken<TitleInterface>('TitleInterface');

Token MY_INTERFACE_TOKEN będzie używany do rejestrowania implementacji interfejsu w systemie DI.

Implementacja interfejsu w dwóch serwisach

Teraz stworzymy dwa serwisy, które będą implementowały interfejs TitleInterface.

// first-title.service.ts
import { Injectable } from '@angular/core';
import { TitleInterface } from './title.interface';

@Injectable({
  providedIn: 'root'
})
export class FirstTitleService implements TitleInterface {
  getTitle(): string {
    return 'Title from FirstTitleService';
  }
}
// second-title.service.ts
import { Injectable } from '@angular/core';
import { TitleInterface } from './title.interface';

@Injectable({
  providedIn: 'root'
})
export class SecondTitleService implements TitleInterface {
  getTitle(): string {
    return 'Title from SecondTitleService';
  }
}

Stworzymy również dwa komponenty, które w providerach mają ustawiony odpowiednią klasę serwisu.

import { Component, inject, signal } from '@angular/core';
import { TITLE_INTERFACE_TOKEN } from './title.token';
import { FirstTitleService } from './first-title.service';

@Component({
  selector: 'app-component-one',
  template: '<p>Component One Title: {{ title() }}</p>',
  providers: [{ provide: TITLE_INTERFACE_TOKEN, useClass: FirstTitleService }],
  standalone: true,
})
export class ComponentOneComponent  {
  private readonly titleService = inject(TITLE_INTERFACE_TOKEN);
  title = signal(this.titleService.getTitle());
}
import { Component, inject, signal } from '@angular/core';
import { TITLE_INTERFACE_TOKEN } from './title.token';
import { SecondTitleService } from './second-title.service';

@Component({
  selector: 'app-component-two',
  template: '<p>Component Two Title: {{ title() }}</p>',
  providers: [{ provide: TITLE_INTERFACE_TOKEN, useClass: SecondTitleService }],
  standalone: true,
})
export class ComponentTwoComponent  {
  private readonly titleService = inject(TITLE_INTERFACE_TOKEN);
  title = signal(this.titleService.getTitle());
}

Czy InjectionToken dla różnych serwisów to rozwiązanie idealne?

Powyższy kod demonstruje użycie InjectionToken w Angularze do wstrzykiwania dwóch różnych implementacji serwisu opartych na wspólnym interfejsie TitleInterface. Dzięki temu komponenty mogą korzystać z różnych serwisów, przypisując ich tytuły do zmiennej title i wyświetlając je w szablonie HTML. Pełny kod znajdziesz pod adresem https://stackblitz.com/~/github.com/tomaszplawecki/inejctiontoken-services

Zalety używania InjectionToken:

  • Elastyczność: Dzięki InjectionToken, możemy łatwo zmienić implementację serwisu dla konkretnego komponentu bez jego modyfikacji.
  • Testowalność: Możliwość łatwego tworzenia mocków dla testów jednostkowych, co zwiększa testowalność kodu.

Wady:

  • Złożoność: Większa elastyczność może prowadzić do większej złożoności kodu, zwłaszcza gdy mamy wiele różnych implementacji.
  • Potencjalne błędy w czasie uruchomienia: Błędy związane z niewłaściwą konfiguracją providerów lub użyciem niewłaściwych typów zależności mogą być trudne do zdiagnozowania.
  • Czytelność: Wielokrotne wstrzykiwanie różnych implementacji serwisów może obniżać czytelność kodu, zwłaszcza dla nowych członków zespołu.

Podsumowując, zastosowanie InjectionToken w Angularze do wstrzykiwania wielu implementacji serwisów oferuje znaczną elastyczność i testowalność, choć wiąże się to również z pewną złożonością, która musi być starannie zarządzana.

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *