Angular предоставляет мощные возможности для создания сервисов, которые можно использовать для централизованного управления состоянием приложения, выполнения бизнес-логики или взаимодействия с внешними источниками данных. Одной из ключевых концепций работы с сервисами в Angular является паттерн синглтон — гарантированное наличие единственного экземпляра сервиса на протяжении всего жизненного цикла приложения или его компонентов.
Паттерн синглтон гарантирует, что существует только один экземпляр определённого класса на протяжении жизни приложения. В контексте Angular это означает, что сервис, использующийся в приложении, будет инстанцироваться один раз, и все компоненты, сервисы или другие зависимости, использующие этот сервис, будут работать с единственным экземпляром.
При правильной реализации синглтона появляется возможность эффективного управления состоянием и предотвращения создания избыточных экземпляров для общих данных или сервисов, что позволяет сэкономить ресурсы.
Angular использует систему инжекции зависимостей (DI), чтобы автоматически управлять жизненным циклом объектов и их зависимостями. Инжекция зависимостей в Angular позволяет сервисам быть автоматически внедрёнными в компоненты, директивы или другие сервисы.
Каждый сервис в Angular может быть зарегистрирован с разным уровнем области видимости:
Для того чтобы сервис стал синглтоном, его нужно зарегистрировать в
корневом инжекторе, используя декоратор @Injectable.
@Injectable и
providedInВ Angular синглтоны создаются через механизм инжекции зависимостей.
Для этого применяется декоратор @Injectable, который
сообщает Angular, что сервис является инжектируемым. Важной особенностью
является использование параметра providedIn, который
определяет область видимости сервиса.
Пример:
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root', // Сервис будет синглтоном во всём приложении
})
export class DataService {
private data: string[] = [];
addData(newData: string): void {
this.data.push(newData);
}
getData(): string[] {
return this.data;
}
}
В данном примере сервис DataService будет единственным
экземпляром в приложении, поскольку он указан в параметре
providedIn: 'root'. Это означает, что Angular создаст один
экземпляр DataService при старте приложения и будет
использовать его везде, где сервис инжектируется.
Когда сервис регистрируется с providedIn: 'root',
Angular создаёт его экземпляр один раз, и он будет доступен на
протяжении всего жизненного цикла приложения. Сервисы с таким уровнем
области видимости остаются живыми до тех пор, пока приложение не
завершит свою работу.
При этом сервисы могут быть использованы не только в компонентах, но и в других сервисах или модулях, благодаря механизмам инжекции зависимостей. Angular автоматически предоставляет нужный экземпляр при запросе, обеспечивая удобство работы и минимизацию кода.
Инжекция синглтона в компоненты происходит автоматически, если в конструкторе компонента указан нужный сервис. При этом Angular гарантирует, что компонент всегда получит единственный экземпляр сервиса.
Пример использования синглтона в компоненте:
import { Component } from '@angular/core';
import { DataService } from './data.service';
@Component({
selector: 'app-my-component',
template: `
<div>
<button (click)="addNewData()">Add Data</button>
<ul>
<li *ngFor="let item of data">{{ item }}</li>
</ul>
</div>
`
})
export class MyComponent {
data: string[] = [];
constructor(private dataService: DataService) {}
addNewData(): void {
this.dataService.addData('New Item');
this.data = this.dataService.getData();
}
}
В данном случае сервис DataService инжектируется в
компонент через конструктор. При вызове метода addNewData()
сервис обновляет данные, которые затем отображаются в компоненте.
Сервисы можно зарегистрировать и на уровне модуля, что создаёт
синглтон в пределах этого модуля. При регистрации сервиса в модуле с
помощью providedIn: 'root' он будет доступен во всей
области видимости приложения. Однако если сервис зарегистрирован только
в определённом модуле, он будет единственным экземпляром только в
пределах этого модуля и не будет доступен в других модулях.
Пример регистрации сервиса на уровне модуля:
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { DataService } from './data.service';
@NgModule({
imports: [CommonModule],
providers: [DataService],
})
export class SharedModule {}
В этом примере сервис будет доступен только в рамках модуля
SharedModule и других компонентов или сервисов, которые
импортируют этот модуль.
Сервисы-синглтоны в Angular являются мощным инструментом для упрощения архитектуры приложений и оптимизации использования ресурсов. Понимание принципов их работы и правильная регистрация через инжекцию зависимостей позволяет создавать эффективные и поддерживаемые приложения. Важно учитывать особенности работы с глобальным состоянием, избегать циклических зависимостей и грамотно организовывать тестирование для обеспечения устойчивости и удобства поддержки приложения в будущем.