Entendendo GoF (Gang of Four) e por que ainda são tão importantes
Se você trabalha com desenvolvimento de software há algum tempo, provavelmente já ouviu falar dos famosos Design Patterns — e principalmente do termo GoF (Gang of Four).
Mas… por que isso ainda importa tanto hoje, em um mundo com microservices, cloud, IA e frameworks cada vez mais abstraídos?
A resposta é simples: problemas clássicos ainda existem — e soluções bem estruturadas continuam sendo valiosas.
📚 O que é GoF?
O termo GoF (Gang of Four) se refere ao livro clássico:
👉 “Design Patterns: Elements of Reusable Object-Oriented Software”
Escrito por quatro autores (Erich Gamma, Richard Helm, Ralph Johnson e John Vlissides), esse livro definiu 23 padrões de projeto que até hoje são referência no desenvolvimento orientado a objetos.
Esses padrões não são código pronto, mas sim formas testadas de resolver problemas recorrentes de design.
🚀 Por que isso ainda é relevante?
Mesmo com frameworks modernos como Spring Boot, Angular, ou arquiteturas baseadas em eventos e cloud:
- Você ainda precisa organizar código
- Precisa garantir baixo acoplamento
- Precisa facilitar manutenção e evolução
- E principalmente: precisa comunicar bem as soluções com o time
👉 E é aí que os padrões brilham.
Eles funcionam como uma linguagem universal entre desenvolvedores.
Quando você fala:
“Aqui usei Strategy”
Outro dev experiente já entende a ideia — sem precisar ler toda a implementação.
🧩 Categorias de padrões GoF
Os padrões do GoF são divididos em três grandes grupos:
- Criacionais → criação de objetos
- Estruturais → organização entre classes
- Comportamentais → comunicação e comportamento entre objetos
👉 E é exatamente aqui que vamos começar.
🎯 O foco deste post: padrões comportamentais
Neste primeiro post, vamos explorar três padrões comportamentais extremamente úteis no dia a dia:
🔁 Strategy
Permite trocar algoritmos de forma dinâmica.
👉 Ideal quando você tem várias formas de executar uma mesma operação.
Exemplo clássico:
- Diferentes formas de cálculo (frete, desconto, imposto)
Abaixo um exemplo utilizando o spring boot, note que dessa forma basta que eu crie novas classes e elas são incluídas na minha lista de forma dinâmica e com isso eu não quebro o Open Closed do SOLID e deixo meu código muito mais organizado
public interface MissaoStrategy {
void execute(MissaoDto missaoDto);
Boolean apply(MissaoDto missaoDto);
}
public class MissaoPsnStrategy implements MissaoStrategy{
@Override
public void execute(MissaoDto missaoDto) {
}
@Override
public Boolean apply(MissaoDto missaoDto) {
return missaoDto.missao().equalsIgnoreCase("psn")
&& missaoDto.type().equalsIgnoreCase("valor");
}
}
public class MissaoNetflixStrategy implements MissaoStrategy{
@Override
public void execute(MissaoDto missaoDto) {
}
@Override
public Boolean apply(MissaoDto missaoDto) {
return missaoDto.missao().equalsIgnoreCase("netflix")
&& missaoDto.type().equalsIgnoreCase("valor");
}
}
@Service
@RequiredArgsConstructor
@Slf4j
public class StrategyServiceApp {
private final List<MissaoStrategy> missaoStrategies;
public void pontuar(MissaoDto missaoDto){
var missao = missaoStrategies.stream()
.filter(missaoStrategy -> missaoStrategy.apply(missaoDto))
.findFirst()
.orElseThrow(() -> new RuntimeException("Missão selecionada é inválida."));
log.debug("missao selecionada: {}", missao.getClass().getSimpleName());
missao.execute(missaoDto);
}
}
👀 Observer
Define um mecanismo de notificação entre objetos.
👉 Muito usado em sistemas orientados a eventos.
Exemplo:
- Um serviço publica um evento e vários consumidores reagem a ele
Abaixo um exemplo utilizando o spring boot, note que dessa forma basta que eu crie novas classes e elas são notificadas de forma que uma não interfere na outra mesmo com regras totalmente diferentes
@Service
@RequiredArgsConstructor
public class ObserverServiceApp {
private final ApplicationEventPublisher eventPublisher;
void notificarMissaoConcluida(Evento evento){
eventPublisher.publishEvent(evento);
}
}
@Service
@RequiredArgsConstructor
@Slf4j
public class EventoNotificarFornecedorAsdf {
@EventListener
void handle(Evento evento){
log.debug("Notificando fornecedor Asdf: {}", evento);
}
}
@Service
@RequiredArgsConstructor
@Slf4j
public class EventoNotificarFornecedorXpto {
@EventListener
void handle(Evento evento){
log.debug("Notificando fornecedor Xpto: {}", evento);
}
}
🔗 Chain of Responsibility
Permite processar uma requisição passando por uma cadeia de handlers.
👉 Cada etapa decide se trata ou passa adiante.
Exemplo:
- Validações em pipeline
- Filtros de autenticação/autorização
💡 Por que começar pelos comportamentais?
Porque eles estão em todo lugar hoje:
- Event-driven architecture → Observer
- Pipelines e middlewares → Chain
- Estratégias dinâmicas → Strategy
👉 Ou seja: mesmo que você não perceba, já está usando esses padrões.
📌 O que vem nos próximos posts?
Este é só o começo.
Nos próximos posts, vamos aprofundar:
- 🏗️ Padrões Criacionais (Factory, Builder, Singleton…)
- 🧱 Padrões Estruturais (Adapter, Facade, Decorator…)
Sempre com exemplos práticos e aplicados ao mundo real (Java, cloud, arquitetura moderna, etc).
🧠 Conclusão
Os padrões GoF não são “velhos” — eles são fundamentais.
Eles ajudam você a:
- escrever código mais limpo
- tomar decisões melhores de arquitetura
- e evoluir sistemas com mais segurança
👉 No fim das contas, não é sobre decorar padrões…
é sobre reconhecer problemas e aplicar boas soluções.