ComponentsDependency Injection
Constructor Injection
Resolve required dependencies from constructor parameters.
Constructor injection is the default component wiring model.
type Mailer interface {
// Send delivers a message without exposing the concrete transport.
Send(to string, body string) error
}
type WelcomeService struct {
mailer Mailer
}
func NewWelcomeService(mailer Mailer) *WelcomeService {
return &WelcomeService{mailer: mailer}
}The constructor signature is the dependency contract. If the container cannot resolve a parameter, component creation fails with an explicit startup error.
WelcomeService does not need to know whether mail is sent through SMTP, a
queue, a test fake, or another implementation. It only needs the Mailer
capability. That is the boundary the constructor exposes to the container.
Multiple dependencies
Add every required dependency to the constructor.
func NewUserService(
repo *UserRepository,
hasher PasswordHasher,
mailer Mailer,
) *UserService {
return &UserService{
repo: repo,
hasher: hasher,
mailer: mailer,
}
}Avoid hidden lookups inside the constructor. Hidden dependencies are harder to test and harder for the container to validate.
