Dependency Inversion Principle

Information

Dependency inversion principle(DIP) states that high-level modules should not depend on low-level modules. Both should depend on abstractions.

The idea is to reduce the coupling between modules, it leads to code being easier to change.

DIP is a way to achieve Open Closed Principle

Example

If we have service that needs repository to work we can inject any implementation of it:

real repository, like mongo or postgres
mock repository for testing
logging repository for debugging without using real database
file repository for some static data
...

In this example we have service that needs repository to work. We can inject any implementation during assembling of components

// abstract module
type Repository interface {
  ...
}
// service implementation
type Service struct {
  repository Repository
}

func NewService(repository Repository) *Service {
  return &Service{repository: repository}
}

func (s *Service) DoSomething(...) {
  s.repository.DoSomethingElse(...)
}
func buildService(cfg Config) Service{
  var repository Repository

  swich cfg.RepositoryType {
  case "mongo":
    repository := mongo.NewRepository(cfg.MongoStuff)
  case "postgres":
    repository := postgres.NewRepository(cfg.PostgresStuff)
  case "logging":
    repository := logging.NewRepository()
  }

  return serviceimplementation.NewService(repository)
}

Resources

#principle