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.