Инверсия контейнера управления (контейнер IoC) - мощный принцип программирования для обработки зависимостей классов. Он используется для увеличения модульности и расширения возможностей программы за счет абстрагирования реализаций через интерфейсы.
Одним из типов IoC является внедрение зависимостей, при котором зависимости вводятся во время выполнения по сравнению с традиционным потоком управления. Все это встроено в Adonis Framework.
Идея
То, что мы собираемся построить, довольно просто, но, надеюсь, достаточно, чтобы доказать элегантность и простоту реализации этой архитектуры. Мы создаем сервис с единственной целью - печатать «привет» и «до свидания» в консоли при посещении определенного маршрута.
Давайте код
Мы будем использовать разные файлы и каталоги для хранения интерфейсов, типов, регистрации привязки и реализации службы.
Стоит отметить, что все примеры кода написаны на TypeScript.
Интерфейс
Интерфейс играет важную роль в отделении деталей реализации от абстракции и дает нам большую гибкость в долгосрочной перспективе.
export default interface GreetingInterface {
sayHello(name: string): void
sayGoodbye(name: string): void
}
Теперь мы создали интерфейс с двумя методами, которые принимают имя в качестве аргумента. Нет никакого возвращаемого типа, так как вывод будет в консоли.
Интерфейс сохраняется в «контрактах / интерфейсах / Greeting.interface.ts».
Реализация
В каталоге «app» создается новая подпапка «Services», которая содержит все детали реализации. В данном случае у меня есть файл GreetingService.ts, реализующий только что созданный интерфейс.
import GreetingInterface from 'Contracts/interfaces/Greeting.interface'
export default class GreetingService implements GreetingInterface { public sayHello (name: string): void { console.log(`Hi ${name}`) }
public sayGoodbye (name: string): void { console.log(`Goodbye ${name}`) } }
Зарегистрируйте привязку
В «Provider / AppProvider.ts» у нас есть возможность зарегистрировать все привязки, используемые в приложении. Существуют разные типы привязок, но в этом примере мы используем шаблон singleton, в котором только один экземпляр создается и используется во всем приложении.
import { IocContract } from '@adonisjs/fold' import GreetingService from 'App/Services/GreetingService'
export default class AppProvider { constructor (protected $container: IocContract) { }
public register () { // Register your own bindings') this.$container.singleton('MyProject/GreetingService', () => new GreetingService()) }
public boot () { // IoC container is ready }
public shutdown () { // Cleanup, since app is going down }
public ready () { // App is ready } }
Чтобы было легче отличать Adonis Core от других привязок, мы используем собственное имя в качестве пространства имен. В этом примере пространство имен называется «MyProject», но это может быть что угодно.
Создайте внешний модуль
Мы создаем внешний модуль, чтобы в полной мере использовать TypeScript и использовать преимущества, которые он дает нам (например, проверка типа). Мы создаем декларацию в папке контракты и называем ее Hello.ts
Чтобы узнать больше об этой концепции, я рекомендую прочитать документацию: https://www.typescriptlang.org/docs/handbook/ modules.html # ambient-modules
declare module '@ioc:MyProject/GreetingService' { import GreetingInterface from 'Contracts/interfaces/Greeting.interface'
const GreetingService: GreetingInterface export default GreetingService }
Эта концепция также используется в Adonis Core.
Последний, но тем не менее важный
Мы завершили настройку минимального контейнера IoC, и пора использовать его в контроллере.
Контроллер создается с помощью «node ace make: controller» и следует стандартной реализации.
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext' import GreetingService from '@ioc:MyProject/GreetingService'
export default class TestController { public async index ({ response }: HttpContextContract) { GreetingService.sayHello('Bob')
// more code .... return response.ok({ data: {}, }) } }