Este projeto demonstra a aplicação do Dependency Inversion Principle (DIP) usando Go através de um exemplo simples e didático: um sistema de cálculo de impostos com diferentes regimes tributários.
O Dependency Inversion Principle estabelece que:
Módulos de alto nível não devem depender de módulos de baixo nível. Ambos devem depender de abstrações.
Em Go, isso significa programar para interfaces, não para implementações concretas.
.
├── cmd/
│ └── main.go # Aplicação principal
├── tax/
│ └── tax.go # Interface Calculator (abstração)
├── internal/
│ ├── calculator/
│ │ ├── simples_nacional.go # Implementação concreta 1
│ │ ├── lucro_presumido.go # Implementação concreta 2
│ │ └── lucro_real.go # Implementação concreta 3
│ └── factory/
│ └── calculator_factory.go # Factory para injeção de dependência
└── .env.example
O arquivo tax/tax.go define a interface Calculator
:
type Calculator interface {
Calculate(revenue float64) float64
GetName() string
}
Três implementações diferentes do cálculo de impostos:
- Simples Nacional (6% de alíquota)
- Lucro Presumido (11.33% de alíquota)
- Lucro Real (15% de alíquota)
Todas implementam a mesma interface Calculator
.
O arquivo internal/factory/calculator_factory.go cria a instância correta baseada na variável de ambiente TAX_REGIME
.
O código em cmd/main.go depende apenas da interface, nunca das implementações concretas:
calculator, err := factory.NewTaxCalculator()
// calculator é do tipo tax.Calculator (interface)
tax := calculator.Calculate(revenue)
git clone https://github.com/matheus-biesek/golang-dependency-injection.git
cd golang-dependency-injection
go mod tidy
Simples Nacional:
TAX_REGIME=SIMPLES go run cmd/main.go
Lucro Presumido:
TAX_REGIME=PRESUMIDO go run cmd/main.go
Lucro Real:
TAX_REGIME=REAL go run cmd/main.go
═══════════════════════════════════════════════════════
Sistema de Cálculo de Impostos
═══════════════════════════════════════════════════════
Regime Tributário: Simples Nacional
Receita: R$ 10000.00
Imposto Calculado: R$ 600.00
═══════════════════════════════════════════════════════
✅ Flexibilidade: Troque a implementação via variável de ambiente sem modificar código
✅ Testabilidade: Fácil criar mocks da interface Calculator
para testes
✅ Manutenibilidade: Adicione novos regimes sem alterar código existente
✅ Desacoplamento: O main.go
não conhece as implementações concretas
✅ Open/Closed Principle: Aberto para extensão, fechado para modificação
- Crie um novo arquivo em
internal/calculator/
implementando a interfaceCalculator
- Adicione um novo case no switch da factory
- Pronto! Sem necessidade de alterar o código principal
- Interface Segregation: Interface pequena e focada
- Dependency Injection: Via factory pattern
- Programação para Interface: O código usa
tax.Calculator
, não os tipos concretos - Factory Pattern: Encapsula a lógica de criação de objetos
Princípio fundamental: Dependa de abstrações (interfaces), não de concretizações (structs).