ES-модуль реализации подхода внедрения зависимостей с использованием шаблона «Сервис-локатор».
npm install @e22m4u/js-service
Для загрузки ES-модуля требуется установить "type": "module"
в файле
package.json
, или использовать .mjs
расширение.
Модуль предлагает классы ServiceContainer
и Service
,
которые можно использовать как по отдельности, так и вместе.
ServiceContainer
- классическая версия сервис-локатораService
- скрывает создание контейнера и его распространение
Класс Service
удобен, когда приложение имеет единственную
точку входа, которая создается оператором new
. Например,
если такой точкой является класс Application
, то мы могли
бы унаследовать его от класса Service
, и обращаться
к другим сервисам методом getService
не заботясь о создании
и хранении их экземпляров.
Кроме того, если другие сервисы так же наследуют от класса
Service
, то они могут обращаться друг к другу используя
тот же метод getService
, как если бы мы передавали
сервис-контейнер между ними.
Методы:
get(ctor, ...args)
получить существующий или новый экземплярhas(ctor)
проверка существования конструктора в контейнереadd(ctor, ...args)
добавить конструктор в контейнерuse(ctor, ...args)
добавить конструктор и создать экземплярset(ctor, service)
добавить конструктор и его экземпляр
Метод get
класса ServiceContainer
создает экземпляр
полученного конструктора и сохраняет его для последующих
обращений по принципу "одиночки".
Пример:
import {ServiceContainer} from '@e22m4u/js-service';
// создание контейнера
const container = new ServiceContainer();
// в качестве сервиса используем класс Date
const myDate1 = container.get(Date); // создание экземпляра
const myDate2 = container.get(Date); // возврат существующего
console.log(myDate1); // Tue Sep 12 2023 19:50:16
console.log(myDate2); // Tue Sep 12 2023 19:50:16
console.log(myDate1 === myDate2); // true
Метод get
может принимать аргументы конструктора. При этом,
если контейнер уже имеет экземпляр данного конструктора, то
он будет пересоздан с новыми аргументами.
Пример:
const myDate1 = container.get(Date, '2025-01-01'); // создание экземпляра
const myDate2 = container.get(Date); // возврат существующего
const myDate3 = container.get(Date, '2025-05-05'); // пересоздание
console.log(myDate1); // Wed Jan 01 2025 03:00:00
console.log(myDate2); // Wed Jan 01 2025 03:00:00
console.log(myDate3); // Sun May 05 2030 03:00:00
Конструктор ServiceContainer
первым параметром принимает родительский
контейнер, который используется как альтернативный, если конструктор
запрашиваемого экземпляра (сервиса) не зарегистрирован в текущем.
class MyService {}
// создание контейнера и регистрация
// в нем сервиса MyService
const parentContainer = new ServiceContainer();
parentContainer.add(MyService);
// использование предыдущего контейнера в качестве родителя,
// и проверка доступности сервиса MyService
const childContainer = new ServiceContainer(parentContainer);
const hasService = childContainer.has(MyService);
console.log(hasService); // true
Методы:
getService(ctor, ...args)
получить существующий или новый экземплярhasService(ctor)
проверка существования конструктора в контейнереaddService(ctor, ...args)
добавить конструктор в контейнерuseService(ctor, ...args)
добавить конструктор и создать экземплярsetService(ctor, service)
добавить конструктор и его экземпляр
Сервисом может являться совершенно любой класс. Однако, если это
наследник класса Service
, то такой сервис позволяет инкапсулировать
создание сервис-контейнера, его хранение и передачу другим сервисам.
Пример:
import {Service} from '@e22m4u/js-service';
// сервис Foo
class Foo extends Service {
method() {
// доступ к сервису Bar
const bar = this.getService(Bar);
// ...
}
}
// сервис Bar
class Bar extends Service {
method() {
// доступ к сервису Foo
const foo = this.getService(Foo);
// ...
}
}
// сервис App (точка входа)
class App extends Service {
method() {
// доступ к сервисам Foo и Bar
const foo = this.getService(Foo);
const bar = this.getService(Bar);
// ...
}
}
const app = new App();
В примере выше мы не заботились о создании сервис-контейнера
и его передачу между сервисами, так как эта логика
инкапсулирована в классе Service
и его методе getService
Метод getService
обеспечивает существование единственного
экземпляра запрашиваемого сервиса, а не создает каждый раз
новый. Тем не менее при передаче дополнительных аргументов,
сервис будет пересоздан с передачей этих аргументов
конструктору.
Пример:
const foo1 = this.getService(Foo, 'arg'); // создание экземпляра
const foo2 = this.getService(Foo); // возврат существующего
console.log(foo1 === foo2); // true
const foo3 = this.getService(Foo, 'arg'); // пересоздание экземпляра
const foo4 = this.getService(Foo); // возврат уже пересозданного
console.log(foo3 === foo4); // true
npm run test
MIT