Ответ
Внедрение зависимостей (Dependency Injection, DI) — это паттерн проектирования, при котором зависимости (объекты, необходимые для работы другого объекта) передаются ему извне, а не создаются им самим.
Это позволяет достичь слабой связанности (loose coupling) между компонентами, что делает код более гибким, модульным и легко тестируемым.
Пример БЕЗ внедрения зависимостей (сильная связанность):
// UserService сам создаёт зависимость от конкретной реализации DB
type UserService struct {
db *PostgresDB // Жёсткая зависимость от *PostgresDB
}
func NewUserService() *UserService {
// Логика создания подключения к БД находится внутри сервиса
return &UserService{db: NewPostgresDB("user:pass@host:port/db")}
}
В этом случае UserService
невозможно протестировать без реальной базы данных Postgres.
Пример С внедрением зависимостей (слабая связанность):
// Определяем интерфейс, который описывает необходимое поведение
_type_ UserStorage _interface_ {
GetUser(id int) (*User, error)
}
// UserService зависит от интерфейса, а не от конкретной реализации
type UserService struct {
storage UserStorage
}
// Зависимость передаётся в конструктор
func NewUserService(storage UserStorage) *UserService {
return &UserService{storage: storage}
}
Основные преимущества:
- Тестируемость: В тестах можно легко подменить реальную зависимость (например, базу данных) на мок-объект (mock), реализующий тот же интерфейс.
- Гибкость: Можно легко заменить одну реализацию зависимости на другую (например,
PostgresDB
наMySQLDB
илиInMemoryDB
), не изменяя кодUserService
. - Переиспользование: Компоненты не привязаны к контексту создания своих зависимостей и могут быть использованы в разных частях системы.
В Go внедрение зависимостей чаще всего реализуется вручную через конструкторы и интерфейсы, как показано в примере. Для сложных графов зависимостей могут использоваться инструменты вроде google/wire
.