Ответ
Обычно это делается через dependency injection (DI). Внешний слой создает экземпляр класса и передает его в бизнес-логику через конструктор или метод.
Пример с TypeScript:
// Внешний слой (например, HTTP-контроллер)
const userRepository = new UserRepository();
const userService = new UserService(userRepository); // DI через конструктор
// Бизнес-логика
class UserService {
constructor(private userRepository: UserRepository) {}
getUser(id: string) {
return this.userRepository.findById(id);
}
}
Ключевые моменты:
- Бизнес-логика не создает зависимости сама
- Внешний слой управляет жизненным циклом зависимостей
- Чистая архитектура: бизнес-логика зависит от абстракций (интерфейсов), а не от конкретных реализаций
Ответ 18+ 🔞
Да ты посмотри, какая хуйня творится в коде обычно! Все эти зависимости, как тараканы, по всему бизнес-слою расползаются. А потом охуеваешь, когда тестить это нельзя, потому что всё намертво прибито гвоздями.
Так вот, слушай сюда, есть же нормальный подход, ёпта! Называется dependency injection, или, по-нашему, "внедрение зависимостей". Суть проще пареной репы: твоя бизнес-логика не должна сама, как последний мудак, создавать себе сервисы и репозитории. Ей это всё должны принести на блюдечке извне!
Смотри, как это выглядит на TypeScript, чтобы не быть голословным:
// Внешний слой (например, HTTP-контроллер)
const userRepository = new UserRepository();
const userService = new UserService(userRepository); // Вот он, DI, через конструктор!
// Бизнес-логика
class UserService {
constructor(private userRepository: UserRepository) {}
getUser(id: string) {
return this.userRepository.findById(id);
}
}
Видишь, в чём фокус? Сервис UserService нихуя не знает, откуда взялся этот userRepository. Ему просто его засунули в конструктор, и он теперь с ним работает. А создал его кто? Внешний слой! Контроллер, скрипт инициализации — кто угодно, но не сама бизнес-логика.
И вот тут три кита, на которых всё держится, блядь:
- Бизнес-логика не создаёт зависимости сама. Она не должна писать
new. Её дело — требовать, чтобы всё нужное ей уже было. Как принцесса, сука. - Внешний слой управляет жизненным циклом. Он решает, когда создать репозиторий, когда его убить, какой именно implementation использовать. Вся эта техническая мутатня — его проблемы.
- Чистая архитектура, мать её. Идеал — когда бизнес-логика зависит не от конкретной, вот этой вот библиотеки для базы данных, а от абстракции, от интерфейса. Типа
IUserRepository. А там уж снаружи подсунут хоть PostgreSQL, хоть MongoDB, хоть файлик на диске. Главное, чтобы контракт соблюдал. Это и есть "зависить от абстракций, а не от реализаций". А иначе — пиши пропало, зарефакторить потом будет овердохуища работы.
Вот так-то, а не "да я тут на коленке в сервисе всё создам". Потом и получается спагетти-код, который только выбросить.