#javascript #node.js #dependency-injection #nestjs
#javascript #node.js #внедрение зависимостей #nestjs
Вопрос:
Пример лучше, чем длинное объяснение:
// Backery.service.ts
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Backery } from './Backery.entity';
@Injectable()
export class BackeryService {
constructor(
@InjectRepository(Backery)
private readonly backeryRepository: Repository<Backery>,
) {}
static myStaticMethodToGetPrice() {
return 1;
}
otherMethod() {
this.backeryRepository.find();
/* ... */
}
}
// Backery.resolver.ts
import { Bakery } from './Bakery.entity';
import { BakeryService } from './Bakery.service';
@Resolver(() => Bakery)
export class BakeryResolver {
constructor() {}
@ResolveField('price', () => Number)
async getPrice(): Promise<number> {
return BakeryService.myStaticMethodToGetPrice(); // No dependency injection here :(
}
}
Как я могу заменить BakeryService.myStaticMethodToGetPrice()
использование внедрения зависимостей, чтобы я мог легко тестировать, например?
Комментарии:
1. Есть ли особая причина, по которой вы хотите, чтобы это был статический метод? Другими словами, почему вы не можете просто ввести
BakeryService
свойBakeryResolver
и вызвать метод price для экземпляра сервиса?2. @eol метод не используется
this
, поэтому более естественно сделать его статическим, поскольку он не зависит от экземпляра объекта.
Ответ №1:
Статические методы не могут использовать внедрение зависимостей. Это потому, что идея внедрения зависимостей (по крайней мере, в Nest) заключается в том, чтобы вводить экземпляры зависимостей, чтобы их можно было использовать позже.
Имеющийся у вас код является допустимым, поскольку он вернет значение 1
, подобное тому, которое указано в статическом методе, но статический метод не может использовать ни одно из введенных значений экземпляра. Вы обнаружите, что такая логика используется в большинстве других фреймворков DI.
Комментарии:
1. Этот код действителен, но является ли он официальной рекомендацией? Или лучше полностью избегать статического метода, чтобы использовать DI и упростить тестирование?
2. Мне нравится избегать статических **, за исключением **, когда дело доходит до динамических модулей.
3. статические методы могут использовать DI, если вы получаете ссылку на объект вашего приложения nest. У него есть метод «resolve», который позволяет вам получать любой объект по типу из его контекста DI
Ответ №2:
Существует очень простой способ создания статических функций, которые используют службы из вашего NestJS DI.
Одним из хороших примеров является использование событий домена и предотвращение загрязнения конструкторов ваших объектов техническими службами.
В вашем main.ts
let app: INestApplication;
async function bootstrap() {
app = await NestFactory.create(AppModule);
install();
...
...
}
bootstrap();
export const getInstance = () => {
return app;
};
Из любого статического контекста в вашем приложении:
import { getInstance } from '@/main';
static async emmitEvent() {
let eventEmitter = await getInstance().resolve(EventEmitter2);
eventEmitter.emit(JSON.stringify(nodeCreateEvent));
}
Комментарии:
1. На самом деле вы не заставили внедрение зависимостей работать со статическими методами, вы просто сделали ссылку на статический метод чем-то, что может использовать внедрение зависимостей. И если вы запустите этот статический метод извне основного приложения, вы получите ошибку времени выполнения из-за того, что метод начальной загрузки, возможно, еще не завершен. Наряду с этим, your
main.ts
теперь используется не только для запуска сервера, что начинает нарушать принцип единой ответственности, который Nest пытается поддержать.2. Не очень понятно, чего именно хочет достичь OP, но мой ответ явно позволяет вам получить доступ к контексту приложения из статического метода. И да, это может привести к сбою, если вы вызовете его по какой-либо причине вне контекста запуска приложения. Что касается единой ответственности — мы предпочитаем, чтобы наши объекты были чистыми, а не вводили, кучу вещей через конструктор и т. Д.