js-service

0

Описание

Реализация принципа инверсии управления (IoC) для JavaScript

Языки

  • JavaScript100%
README.md

@e22m4u/js-service

npm version license

Модуль реализует принцип инверсии управления (Inversion of Control), через паттерн Service Locator в связке с DI-контейнером. Встроенные классы данного модуля берут на себя ответственность за создание, хранение и жизненный цикл объектов, освобождая зависимости приложения от жестких связей и ручного вызова конструкторов.

Содержание

Установка

Модуль поддерживает ESM и CommonJS стандарты.

ESM

CommonJS

Описание

Модуль экспортирует два основных класса

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

  • ServiceContainer
    (IoC-контейнер)
    Реализация сервис-контейнера для хранения и разрешения зависимостей.

  • Service
    (базовый класс для наследования сервисами)
    Инкапсулирует работу с сервис-контейнером, предоставляя наследуемым от него сервисам простой интерфейс для доступа к зависимостям.

Дополнительно:

  • DebuggableService
    (базовый Service + инструменты логирования)
    Расширенная версия класса
    Service
    с дополнительным функционалом для логирования.

Базовые примеры

Создание контейнера и экземпляра сервиса по принципу «одиночки».

Использование сервиса внутри другого как зависимость.

Сервис как точка входа приложения.

Подмена сервиса в контейнере.

ServiceContainer

В роли IoC-контейнера выступает класс

ServiceContainer
. Он отвечает за регистрацию, создание и предоставление экземпляров сервисов (зависимостей).

Методы:

  • get(ctor, ...args)
    получить существующий или новый экземпляр;
  • getRegistered(ctor, ...args)
    получить существующий или новый экземпляр, только если указанный конструктор зарегистрирован в контейнере, в противном случае выбрасывается ошибка;
  • has(ctor)
    проверить существование конструктора в контейнере;
  • add(ctor, ...args)
    добавить конструктор в контейнер (ленивая инициализация);
  • use(ctor, ...args)
    добавить конструктор и сразу создать экземпляр;
  • set(ctor, service)
    добавить конструктор и связанный с ним готовый экземпляр;
  • getParent()
    получить родительский сервис-контейнер;
  • hasParent()
    проверить наличие родительского сервис-контейнера;

В сигнатурах методов используется вспомогательный тип конструктора:

serviceContainer.get

Метод

get
класса
ServiceContainer
создает экземпляр полученного конструктора и сохраняет его для последующих обращений по принципу "одиночки" (Singleton).

Сигнатура:

Пример:

Метод

get
может принимать аргументы конструктора. При этом, если контейнер уже имеет экземпляр данного конструктора, то он будет пересоздан с новыми аргументами.

Пример:

serviceContainer.getRegistered

Работает аналогично

get
, но выбрасывает ошибку, если конструктор сервиса не был предварительно зарегистрирован через
add
,
use
или
set
. Это обеспечивает более строгий контроль над зависимостями.

Сигнатура:

Пример:

serviceContainer.has

Проверяет, зарегистрирован ли конструктор в контейнере (или в одном из его родительских контейнеров). Возвращает

true
или
false
.

Сигнатура:

Пример:

serviceContainer.add

Регистрирует конструктор в контейнере, но не создает экземпляр в момент вызова. Экземпляр будет создан только при первом доступе к сервису. Метод позволяет указать аргументы, которые будут использованы для создания экземпляра.

Сигнатура:

Пример:

Аргументы, переданные в

add
, будут использованы при создании экземпляра, если
get
будет вызван без аргументов.

serviceContainer.use

Немедленно создает и кэширует экземпляр сервиса. Может использоваться, когда сервис должен быть проинициализирован сразу при настройке другого компонента.

Сигнатура:

Пример:

serviceContainer.set

Метод позволяет связать конструктор с уже существующим экземпляром. Может быть использован для подмены зависимостей в тестах или для внедрения экземпляров, созданных вне контейнера.

Сигнатура:

Пример:

serviceContainer.getParent

Метод возвращает родительский контейнер. Если у текущего контейнера нет родителя, то метод выбрасывает ошибку.

Сигнатура:

Пример:

serviceContainer.hasParent

Метод проверяет наличие родительского контейнера и возвращает логическое значение. Данный метод полезен перед вызовом метода

getParent
, который выбрасывает ошибку при отсутствии родителя.

Сигнатура:

Пример:

Иерархия контейнеров

Конструктор

ServiceContainer
первым параметром принимает родительский контейнер, который используется как альтернативный, если конструктор запрашиваемого сервиса не зарегистрирован в текущем.

Service

Методы:

  • getService(ctor, ...args)
    получить существующий или новый экземпляр;
  • getRegisteredService(ctor, ...args)
    получить существующий или новый экземпляр, только если указанный конструктор зарегистрирован в контейнере, в противном случае выбрасывается ошибка;
  • hasService(ctor)
    проверить существование конструктора в контейнере;
  • addService(ctor, ...args)
    добавить конструктор в контейнер;
  • useService(ctor, ...args)
    добавить конструктор и создать экземпляр;
  • setService(ctor, service)
    добавить конструктор и его экземпляр;

Сервисом может являться совершенно любой класс. Однако, если это наследник класса

Service
, то такой сервис позволяет инкапсулировать создание сервис-контейнера, его хранение и передачу другим сервисам.

Пример:

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

Service
.

service.getService

Метод

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

Сигнатура:

Пример:

service.getRegisteredService

Работает аналогично

getService
, но выбрасывает ошибку, если конструктор сервиса не был предварительно зарегистрирован, что обеспечивает более строгий контроль над зависимостями.

Сигнатура:

Пример:

service.hasService

Проверяет, зарегистрирован ли конструктор в контейнере. Возвращает

true
или
false
. Полезно для условного запроса зависимостей.

Сигнатура:

Пример:

service.addService

Регистрирует конструктор в контейнере, но не создает экземпляр в момент вызова. Экземпляр будет создан только при первом доступе к сервису. Метод позволяет указать аргументы, которые будут использованы для создания экземпляра.

Сигнатура:

Пример:

service.useService

Немедленно создает и кэширует экземпляр сервиса. Может использоваться, когда сервис должен быть проинициализирован сразу при настройке другого компонента.

Сигнатура:

Пример:

service.setService

Метод позволяет связать конструктор с уже существующим экземпляром. Может быть использован для подмены зависимостей в тестах или для внедрения экземпляров, созданных вне контейнера.

Сигнатура:

Пример:

DebuggableService

Данный сервис наследует класс

Debuggable
и использует композицию для получения функциональности класса
Service
.
(см. подробнее @e22m4u/js-debug раздел «Класс Debuggable»)

Тесты

Лицензия

MIT