Registry
Definição (Fowler)
Seção intitulada “Definição (Fowler)”“A well-known object that other objects can use to find common objects and services.”
Em vez de passar uma dependência de objeto em objeto, o cliente pergunta ao Registry: “me dê o serviço X”. O Registry guarda referências globalmente acessíveis.
Problema que (aparentemente) resolve
Seção intitulada “Problema que (aparentemente) resolve”Como um objeto encontra um serviço compartilhado sem recebê-lo explicitamente? O Registry oferece um endereço global. Historicamente resolvia a ausência de um contêiner de injeção: bastava um Registry.get(Servico.class).
Trade-offs (e por que é problemático)
Seção intitulada “Trade-offs (e por que é problemático)”| “Vantagem” | Custo real |
|---|---|
| Acesso global fácil | Dependências ocultas: a assinatura não revela o que a classe usa |
| Sem “passar” dependências | Acoplamento a um singleton global |
| Simples de chamar | Testabilidade ruim: difícil substituir por dublês |
| — | Estado global compartilhado (problemas de concorrência) |
| — | Fere o DIP - Dependency Inversion Principle e o SRP - Single Responsibility Principle |
Quando (ainda) pode aparecer
Seção intitulada “Quando (ainda) pode aparecer”- Pontos de entrada onde não há contêiner de DI (bootstrap, integração com frameworks legados).
- Como implementação interna de um contêiner de DI (o próprio contêiner é, no fundo, um registry sofisticado) — mas aí o acesso não é global e disperso.
Ponto-chave: DI substitui Registry
Seção intitulada “Ponto-chave: DI substitui Registry”A injeção de dependência inverte o fluxo: em vez do objeto buscar suas dependências no Registry (Service Locator), ele as recebe de fora (via construtor). As dependências ficam explícitas e substituíveis.
graph TD
subgraph "Registry / Service Locator (cheiro)"
C1[Cliente] -->|get Servico| R[(Registry global)]
R --> S1[Servico]
end
subgraph "Injeção de Dependência (preferível)"
Cont[Contêiner Spring] -->|injeta no construtor| C2[Cliente]
C2 --> S2[Servico]
end
Exemplo Java/Spring
Seção intitulada “Exemplo Java/Spring”Registry clássico (anti-exemplo a ser evitado):
public final class ServiceRegistry {
private static final Map<Class<?>, Object> SERVICES = new ConcurrentHashMap<>();
private ServiceRegistry() {}
public static <T> void register(Class<T> tipo, T instancia) { SERVICES.put(tipo, instancia); }
@SuppressWarnings("unchecked") public static <T> T get(Class<T> tipo) { T s = (T) SERVICES.get(tipo); if (s == null) { throw new IllegalStateException("Serviço não registrado: " + tipo); } return s; }}
public class PedidoService { public void confirmar(Long id) { var repo = ServiceRegistry.get(PedidoRepository.class); repo.findById(id).orElseThrow().confirmar(); }}Problemas: PedidoService esconde que depende de PedidoRepository; testá-lo exige manipular o estado global estático; qualquer classe pode alterar o registry.
Forma moderna equivalente, com injeção de dependência (preferir):
@Servicepublic class PedidoService {
private final PedidoRepository repo;
public PedidoService(PedidoRepository repo) { this.repo = repo; }
@Transactional public void confirmar(Long id) { Pedido pedido = repo.findById(id).orElseThrow(); pedido.confirmar(); repo.save(pedido); }}A dependência é explícita no construtor, o Spring a resolve, e o teste injeta um mock diretamente — sem estado global.
Anti-padrões e erros comuns
Seção intitulada “Anti-padrões e erros comuns”- Service Locator disfarçado: usar
ApplicationContext.getBean(...)espalhado pelo código em vez de injeção por construtor — recria o Registry dentro do Spring. - Dependências ocultas: classes cuja assinatura não revela suas dependências.
- Estado global mutável:
register/setchamáveis em runtime, criando acoplamento temporal e problemas de concorrência. - Dificuldade de teste: precisar montar/desmontar estado estático entre testes.
- Justificar Registry “por simplicidade” onde já existe um contêiner de DI disponível.
Relações
Seção intitulada “Relações”- Substituído por injeção de dependência, guiada pelo DIP - Dependency Inversion Principle.
- É uma forma de estado global; relaciona-se a Code Smells e Code Smells e SOLID.
- Fere o SRP - Single Responsibility Principle ao acoplar localização + uso.
- Prejudica Testabilidade e Arquitetura.
- Índice: PoEAA.
Perguntas de revisão
Seção intitulada “Perguntas de revisão”1. O que é o Registry e a que padrão de objeto ele equivale?
Resposta
Um ponto global e conhecido para localizar objetos/serviços. Equivale, na essência, a um Singleton global (uma forma de Service Locator).
2. Por que o Registry é considerado um cheiro?
Resposta
Porque torna as dependências implícitas (não aparecem na assinatura), introduz estado global, dificulta testes e viola o DIP — o objeto busca suas dependências em vez de recebê-las.
3. Como a injeção de dependência resolve isso?
Resposta
Invertendo o fluxo: as dependências são injetadas (via construtor) e ficam explícitas e substituíveis, sem acoplamento a um singleton global. O contêiner (ex.: Spring) resolve o grafo.
4. Usar ApplicationContext.getBean(...) espalhado é aceitável?
Resposta
Não como prática geral: é um Service Locator disfarçado dentro do Spring, recriando os problemas do Registry. Prefira injeção por construtor; reserve getBean para casos de bootstrap/integração muito específicos.