Pular para o conteúdo principal

Registry

Descrição​

O Registry é um objeto bem conhecido que outros objetos usam para encontrar objetos e serviços comuns. Normalmente se chega a objetos relacionados navegando a partir de outro que já se tem (de um cliente, chega-se aos pedidos). Isso falha quando só se possui um identificador, sem nenhuma referência: é preciso um objeto localizador, e surge a pergunta de como alcançar o próprio localizador.

O Registry responde a essa pergunta: é um ponto de acesso conhecido, que se comporta como um objeto global, mas que pode ser menos global do que parece (por exemplo, restrito a uma thread, a uma requisição ou a uma sessão). Quem precisa de um serviço ou de um finder pergunta ao Registry.

O Registry é um padrão de último recurso: quando possível, passar as dependências explicitamente (por parâmetro ou injeção de dependência) é preferível.

Problemas que resolve​

  • Objetos precisam alcançar serviços ou finders comuns sem ter referência a eles.
  • Passar a mesma dependência por muitas camadas intermediárias polui as assinaturas.
  • Falta de um ponto de entrada conhecido para localizar objetos compartilhados.

Quando usar​

  • Quando muitos pontos do sistema precisam de acesso a objetos ou serviços comuns e passá-los adiante seria impraticável.
  • Quando se tem apenas um identificador e é preciso resolvê-lo para um objeto, por exemplo via Repository ou finder.
  • Em código legado ou frameworks onde não há injeção de dependência disponível.

Quando evitar​

  • Quando a injeção de dependência é viável: dependências explícitas deixam o código mais claro e testável.
  • Quando o Registry viraria um estado global mutável compartilhado, o que dificulta testes e concorrência.
  • Quando as dependências ocultas tornam o código difícil de entender, pois a assinatura não revela o que a classe usa.

Trade-offs​

GanhoCusto / Risco
Acesso simples a serviços comuns de qualquer pontoDependências ocultas: a assinatura não mostra o que o código usa
Evita passar parâmetros por muitas camadasComporta-se como estado global, dificultando o isolamento
Ponto único para trocar implementações (testes, ambientes)Testes em paralelo podem interferir entre si
Fácil de implementarRisco de acoplamento a um ponto central e de uso excessivo
  • Testabilidade: exige que o Registry permita substituir as implementações (por exemplo, um método para instalar um stub) e que os testes o restaurem.
  • Concorrência: Fowler discute registries por thread, por sessão ou por requisição para evitar compartilhamento indevido.

Diagrama​

O Client pede ao Registry o PersonFinder ou o OrderService de que precisa, sem ter recebido nenhum deles por parâmetro.

Exemplo​

Um código legado precisa do finder de pessoas em vários pontos. O Registry expõe um acesso estático e permite trocar a implementação em testes.

public class Registry {
private static Registry instance = new Registry();
private PersonFinder personFinder = new DatabasePersonFinder();

public static PersonFinder personFinder() {
return instance.personFinder;
}

// Uso em testes: instala um stub e reinicia o estado
public static void initializeForTests(PersonFinder stub) {
instance = new Registry();
instance.personFinder = stub;
}

public static void reset() {
instance = new Registry();
}
}

// Cliente
Person person = Registry.personFinder().find(42L);

Localizadores de serviço (ServiceLocator) e contextos de aplicação consultados manualmente são variações do Registry.

Padrões relacionados​

  • Singleton — o Registry costuma ser implementado como Singleton, mas o Singleton garante uma instância, e o Registry fornece um ponto de acesso para localizar vários objetos.
  • Service Registry — não confundir: aquele é um banco de dados de instâncias de serviços na rede para descoberta; o Registry do PoEAA é um objeto dentro de um processo que localiza objetos locais.
  • Separated Interface — o Registry pode devolver a implementação associada à interface.
  • Plugin — alternativa baseada em configuração para escolher implementações.
  • Gateway — gateways são exemplos típicos do que se obtém por um Registry.
  • Repository — finders e repositórios são objetos frequentemente localizados por um Registry.
  • Factory Method — também centraliza a obtenção de objetos, mas cria instâncias em vez de localizar objetos existentes.

Referência​