Перейти к содержанию

Создание инжектируемой службы

📅 2.08.2022

Сервис — это широкая категория, охватывающая любые ценности, функции или возможности, необходимые приложению. Обычно сервис — это класс с узкой, четко определенной целью. Компонент — это один из типов классов, который может использовать DI.

Angular отличает компоненты от сервисов для повышения модульности и возможности повторного использования. Отделяя функции компонента, связанные с представлением, от других видов обработки, вы можете сделать свои классы компонентов компактными и эффективными.

В идеале задача компонента — обеспечить удобство работы пользователя и не более того. Компонент должен представлять свойства и методы для связывания данных, чтобы быть посредником между представлением (отображаемым шаблоном) и логикой приложения (которая часто включает в себя некоторое понятие модели).

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

Angular не навязывает эти принципы. Angular помогает вам следовать этим принципам, упрощая разделение логики приложения на сервисы и делая эти сервисы доступными для компонентов через DI.

Примеры сервисов

Вот пример класса сервиса, который ведет журнал в консоль браузера.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
export class Logger {
    log(msg: any) {
        console.log(msg);
    }
    error(msg: any) {
        console.error(msg);
    }
    warn(msg: any) {
        console.warn(msg);
    }
}

Сервисы могут зависеть от других сервисов. Например, вот HeroService, который зависит от сервиса Logger, а также использует BackendService для получения героев.

Этот сервис, в свою очередь, может зависеть от сервиса HttpClient для асинхронного получения героев с сервера.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
export class HeroService {
    private heroes: Hero[] = [];

    constructor(
        private backend: BackendService,
        private logger: Logger
    ) {}

    getHeroes() {
        this.backend.getAll(Hero).then((heroes: Hero[]) => {
            this.logger.log(
                `Fetched ${heroes.length} heroes.`
            );
            this.heroes.push(...heroes); // fill cache
        });
        return this.heroes;
    }
}

Создание инжектируемого сервиса

Angular CLI предоставляет команду для создания нового сервиса. В следующем примере вы добавляете новый сервис в ваше приложение, которое было создано ранее с помощью команды ng new.

Чтобы создать новый класс HeroService в папке src/app/heroes, выполните следующие шаги:

  1. Выполните эту команду Angular CLI:

    1
    ng generate service heroes/hero
    

    Эта команда создает следующую службу по умолчанию HeroService.

    1
    2
    3
    4
    5
    6
    import { Injectable } from '@angular/core';
    
    @Injectable({
        providedIn: 'root',
    })
    export class HeroService {}
    

    Декоратор @Injectable() указывает, что Angular может использовать этот класс в системе DI. Метаданные providedIn: 'root' означают, что HeroService виден во всем приложении.

  2. Добавьте метод getHeroes(), который возвращает героев из mock.heroes.ts для получения имитационных данных героев:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    import { Injectable } from '@angular/core';
    import { HEROES } from './mock-heroes';
    
    @Injectable({
        // declares that this service should be created
        // by the root application injector.
        providedIn: 'root',
    })
    export class HeroService {
        getHeroes() {
            return HEROES;
        }
    }
    

    Для ясности и удобства сопровождения рекомендуется определять компоненты и сервисы в отдельных файлах.

Инжектирование сервисов

Чтобы внедрить сервис в качестве зависимости в компонент, вы можете использовать функцию constructor() компонента и указать в аргументе конструктора тип зависимости. Следующий пример указывает HeroService в конструкторе HeroListComponent. Тип heroServiceHeroService. Angular распознает HeroService как зависимость, поскольку этот класс был ранее аннотирован декоратором @Injectable.

1
constructor(heroService: HeroService)

Инжектирование сервисов в другие сервисы

Когда сервис зависит от другого сервиса, следуйте той же схеме, что и при инъекции в компонент. В следующем примере HeroService зависит от сервиса Logger, чтобы сообщать о своих действиях.

Сначала импортируйте службу Logger. Затем внедрите службу Logger в конструктор() службы HeroService, указав private logger: Logger.

Здесь constructor() указывает тип Logger и хранит экземпляр Logger в приватном поле logger.

В следующих вкладках кода представлены сервис Logger и две версии HeroService. Первая версия HeroService не зависит от сервиса Logger. Переработанная вторая версия зависит от службы Logger.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
import { Injectable } from '@angular/core';
import { HEROES } from './mock-heroes';
import { Logger } from '../logger.service';

@Injectable({
    providedIn: 'root',
})
export class HeroService {
    constructor(private logger: Logger) {}

    getHeroes() {
        this.logger.log('Getting heroes ...');
        return HEROES;
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
import { Injectable } from '@angular/core';
import { HEROES } from './mock-heroes';

@Injectable({
    providedIn: 'root',
})
export class HeroService {
    getHeroes() {
        return HEROES;
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
import { Injectable } from '@angular/core';

@Injectable({
    providedIn: 'root',
})
export class Logger {
    logs: string[] = []; // capture logs for testing

    log(message: string) {
        this.logs.push(message);
        console.log(message);
    }
}

В этом примере метод getHeroes() использует службу Logger, записывая в журнал сообщение при получении героев.

Что дальше

Комментарии