В чем разница между IoC (Inversion of Control) и DI (Dependency Injection)?

Ответ

IoC (Инверсия управления) — это общий архитектурный принцип, при котором управление потоком выполнения или вызовом компонентов делегируется внешнему фреймворку или контейнеру, а не контролируется самим кодом приложения.

DI (Внедрение зависимостей) — это конкретный шаблон проектирования, реализующий IoC. Зависимости объекта не создаются им самим, а "внедряются" извне (обычно контейнером).

Ключевое отличие: DI — это частный случай IoC. IoC может быть реализован и другими способами (например, через шаблон Factory или Service Locator).

Пример DI в Spring:

// Зависимость
interface Repository { /* ... */ }

// Сервис, получающий зависимость через конструктор (Constructor Injection)
@Service
public class MyService {
    private final Repository repository;

    @Autowired // Контейнер Spring внедрит реализацию Repository
    public MyService(Repository repository) {
        this.repository = repository; // Зависимость предоставлена извне
    }
}

Почему это важно: DI делает код более тестируемым, слабосвязанным и управляемым, так как зависимости можно легко подменить (например, на моки в unit-тестах).

Ответ 18+ 🔞

Давайте разберёмся, что за зверь такой этот IoC и его верный пёс DI, а то ведь многие их путают, как хуй с пальто, и потом в коде пиздец творится.

IoC (Инверсия управления) — это, блядь, как если бы ты обычно сам себе бутерброд мазал, а тут приходит официант-фреймворк, выхватывает у тебя нож и говорит: «Сиди, мудак, я всё сам сделаю, а ты просто жди». То есть управление потоком выполнения вырывается из твоих рук и отдаётся какому-то внешнему контейнеру. Ты больше не царь и бог, ты просто просишь: «Эй, дай мне вот это», а он тебе подсовывает.

DI (Внедрение зависимостей) — это уже конкретная технология, как этот официант будет тебе этот бутерброд впихивать. Не ты лезешь в холодильник за колбасой, а тебе её суют прямо в рот (или, что более прилично, в конструктор). Зависимости объекта не создаются внутри него — их ему внедряют извне. Это и есть главный пиздец, то есть принцип.

Чем они отличаются, ёпта? DI — это частный, самый распиздяйски популярный случай IoC. IoC — понятие широкое, как жопа у слона. Его можно реализовать и через фабрики, и через сервис-локаторы, но DI — это когда тебе прямо в поля или конструктор тычут готовые штуки.

Смотри, как это выглядит в Spring, чтобы не быть просто пиздаболом:

// Допустим, есть какой-то интерфейс, который нам нужен
interface Repository { /* ... */ }

// А вот сервис, который хочет эту зависимость
@Service
public class MyService {
    private final Repository repository; // Храним её тут, как жадный пиздюк

    @Autowired // А это волшебная надпись: "Спринг, будь другом, впендюрь сюда реализацию!"
    public MyService(Repository repository) {
        this.repository = repository; // И вот она, зависимость, прилетела снаружи! Мы её не создавали!
    }
}

А нахуя это всё? Да затем, что код становится тестируемым, как швейцарские часы, и слабосвязанным. Захотел потестить — подсунул в конструктор мок (заглушку), а не реальную базу данных, которая нахуй не нужна в unit-тесте. Всё гибко, всё управляемо. А без этого — сам себе злобный буратино, который всё держит в кулачке и потом охуевает, когда надо что-то поменять.