Как ссылка на instance класса попадает из наружного слоя в бизнес-логику

Ответ

Обычно это делается через 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);
  }
}

Ключевые моменты:

  1. Бизнес-логика не создает зависимости сама
  2. Внешний слой управляет жизненным циклом зависимостей
  3. Чистая архитектура: бизнес-логика зависит от абстракций (интерфейсов), а не от конкретных реализаций

Ответ 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. Ему просто его засунули в конструктор, и он теперь с ним работает. А создал его кто? Внешний слой! Контроллер, скрипт инициализации — кто угодно, но не сама бизнес-логика.

И вот тут три кита, на которых всё держится, блядь:

  1. Бизнес-логика не создаёт зависимости сама. Она не должна писать new. Её дело — требовать, чтобы всё нужное ей уже было. Как принцесса, сука.
  2. Внешний слой управляет жизненным циклом. Он решает, когда создать репозиторий, когда его убить, какой именно implementation использовать. Вся эта техническая мутатня — его проблемы.
  3. Чистая архитектура, мать её. Идеал — когда бизнес-логика зависит не от конкретной, вот этой вот библиотеки для базы данных, а от абстракции, от интерфейса. Типа IUserRepository. А там уж снаружи подсунут хоть PostgreSQL, хоть MongoDB, хоть файлик на диске. Главное, чтобы контракт соблюдал. Это и есть "зависить от абстракций, а не от реализаций". А иначе — пиши пропало, зарефакторить потом будет овердохуища работы.

Вот так-то, а не "да я тут на коленке в сервисе всё создам". Потом и получается спагетти-код, который только выбросить.