Skip to main content
Практика завдань

Розширені патерни впровадження залежностей в Angular

Розширені патерни DI

Система впровадження залежностей Angular виходить за межі базового впровадження сервісів. Розуміння розширених патернів є критично важливим для створення масштабованих додатків.


Багато постачальників

Зареєструйте кілька значень для одного й того ж токена:

typescript
const HTTP_INTERCEPTORS = new InjectionToken<HttpInterceptor[]>('interceptors'); // Кожен постачальник ДОДАЄ до масиву providers: [ { provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true }, { provide: HTTP_INTERCEPTORS, useClass: LoggingInterceptor, multi: true }, { provide: HTTP_INTERCEPTORS, useClass: ErrorInterceptor, multi: true }, ] // Впровадження отримує ВСІ з них constructor(@Inject(HTTP_INTERCEPTORS) private interceptors: HttpInterceptor[]) { // interceptors = [AuthInterceptor, LoggingInterceptor, ErrorInterceptor] }

Фабричні постачальники

Створюйте залежності з динамічною логікою:

typescript
{ provide: LoggerService, useFactory: () => { const env = inject(EnvironmentService); return env.isProduction ? new ProductionLogger() : new ConsoleLogger(); } }

Опціональні та Self/SkipSelf

typescript
@Component({ /* ... */ }) export class MyComponent { // Не викличе помилку, якщо не знайдено constructor(@Optional() private analytics?: AnalyticsService) {} // Шукає тільки в ІН'ЄКТОРІ цього компонента constructor(@Self() private service: MyService) {} // Пропускає ЦЕЙ ін'єктор, шукає в батьківському constructor(@SkipSelf() private service: MyService) {} }

Tree-Shakeable постачальники

typescript
// ✅ Tree-shakeable — видаляється, якщо не впроваджено ніде @Injectable({ providedIn: 'root' }) export class UserService {} // ❌ Не tree-shakeable — завжди включається @NgModule({ providers: [UserService] }) export class UserModule {}

Постачальники на рівні компонента

typescript
// Кожен екземпляр компонента отримує СВІЙ власний екземпляр сервісу @Component({ providers: [FormStateService] // Не ділиться з іншими компонентами }) export class FormComponent { constructor(private formState: FormStateService) {} // Кожен FormComponent має свій власний FormStateService }

Абстрактний клас як токен

typescript
// Визначити абстрактний контракт abstract class Storage { abstract get(key: string): string | null; abstract set(key: string, value: string): void; } // Реалізація class LocalStorageService extends Storage { get(key: string) { return localStorage.getItem(key); } set(key: string, value: string) { localStorage.setItem(key, value); } } // Надати реалізацію { provide: Storage, useClass: LocalStorageService } // Впровадження абстракції constructor(private storage: Storage) { this.storage.get('token'); // Використовує LocalStorageService }

Конфігурація на основі середовища

typescript
export const APP_CONFIG = new InjectionToken<AppConfig>('app.config'); // У main.ts bootstrapApplication(AppComponent, { providers: [ { provide: APP_CONFIG, useValue: { apiUrl: environment.apiUrl, debug: !environment.production, features: environment.features, } } ] }); // У будь-якому сервісі/компоненті private config = inject(APP_CONFIG);

Важливо:

Розширені патерни DI включають багато постачальників (системи плагінів, перехоплювачі), фабричні постачальники (умовна логіка) та абстрактні класи токенів (чисті інтерфейси). Використовуйте providedIn: 'root' для tree-shakeable синглтонів. Використовуйте постачальників на рівні компонента для ізольованих екземплярів. Розуміння ієрархії DI (Self, SkipSelf, Optional) є ключовим для складних додатків.

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.

Дочитали статтю?
Практика завдань