Registry

Objetivo

Prover uma forma de objetos contactarem outros objetos de forma desacoplada de ambos.

Propósito

Uma aplicação funciona pela colaboração entre objetos, portanto a primeira coisa necessária é que o objeto executor possa encontrar o seu colaborador. Esta colaboração cria uma dependência entre o objeto executor e aquele que ele necessita para executar a sua tarefa.

A injeção de dependência (passar o objeto colaborador como argumento do construtor do objeto executor) é uma opção viável mas que acopla para sempre as instancias de ambos objetos.

Por outro lado, o fato de ser necessária a colaboração de um objeto de um certo tipo, isso não significa que esse colaborador não possa ser modificado ou substituído por outro. Além disso, duas instâncias da mesma classe podem ser configuradas de forma diferente para realizar a mesma operação de forma diferente ou sobre um contexto diferente. O padrão Registry (Registro) oferece portanto um nível maior de configuração de qual instancia irá desempenhar o trabalho.

Se desacoplamos os objetos precisamos de um ponto de encontro em é garantido que o colaborador esteja presente e onde é garantido que o objeto trabalhador o irá procurar. Consequentemente este será um ponto de acesso global.

Implementação

A forma mais simples de implmentar o padrão Registry é criar uma classe não extensível e não instanciável onde podemos registrar o objeto colaborador e onde o objeto executor irá procurá-la.

public final class Registry { // não extensivel

	private Registry(){} // não instanciável e não extensivel

	private static Dictionary dictionary;

	public static Dictionary getDictionary(){
		return dictionary;
	}

	public static void setDictionary(Dictionary aDictionary){
		dictionary = aDictionary;
	}

}

Qualquer objeto que precise utilizar um dicionário agora sabe como obtê-lo sem se preocupar com a classe verdadeira desse objeto. Em particular, o registro pode ser

Imaginando que Dictionary é uma interface, poderíamos ter classes PtDictionary , EnDictionary e EsDictionary e escolher no inicio da aplicação qual usar.

public class Main{

	public static final void main(String[] args){

		// registra a utilização do dicionario ingles.
		Registry.setDictionary(new EnDictionary());

	}
}

Se a aplicação faz traduções então é necessário utilizar mais do que um dicionario. Poderíamos criar um método de registro para cada um, mas isso seria penoso. É mais fácil utilizar uma chave de registro. A chave de registro é um outro objeto (normalmente um String, mas não precisa ser sempre) que permite recuperar o objeto depois.

No nosso caso utilizaremos um String representando a língua.Repare como a estrutura interna foi alterada para usar um Map.

public final class Registry { // não extensivel

	private Registry(){} // não instanciável e não extensivel

	private static final Map<String,Dictionary> dictionaries = new HashMap<>();

	public static Dictionary getDictionary(String language){
		return dictionaries.get(language);
	}

	public static void addDictionary(String language,Dictionary dictionary){
		dictionaries.put(language, dictionary);
	}

}

Repare que a implementação é muito semelhante a um Property Bag mas onde os métodos acessores e modificadores são estáticos.

Registros e Repositórios

Um uso comum para o padrão Registry é servir como ponto de encontro de objetos que implementam o padrão Repository. Um repositório está associado a uma entidade - mais especificamente um agregado - que é representada por uma classe.

Poderíamos registrar um repositório com um método de registro para cada entidade, mas seria mais interessante utilizar a entidade ( a classe da entidade) como chave do registro.

O exemplo a seguir assume que existe um tipo Repository<E> genéricamente tipado.

public final class Repositories { // não extensivel

	private Repositories(){} // não instanciável e não extensivel

	private static final Map<String,Repository> repositories = new HashMap<>();

	public static <E> Repository<E> forEntity(Class<E> entityType){
		return repositories.get(entityType.getName());
	}

	public static <E> void addRepository(Class<E> entityType, Repository<E> repository){
		repositories.put( entityType.getName(),repository);
	}

}

Exemplos na API padrão

O padrão Registry está presente na API padrão na classe System de onde podem se obter e registrar vários objetos uteis. Particularmente System.getProperty(), System.out e System.in

Além disso o padrão Registry está presente em DriveManager.getConnection().

Generalização

Como vemos, um objeto que implemente o padrão Registry pode ser muito útil. Existe acesso global aos objetos registrados e podemos utilizar chaves de registro para diferenciar entre objetos

Este padrão é tão útil que é seguido pela tecnologia Java Name and Directory Interface (JNDI). Esta tecnologia da plataforma java utiliza caminhos como chaves de registro permitindo não apenas registrar os objetos, mas também registrá-los segundo uma hierarquia. Além, disso permite que o registro e a recuperação dos objetos seja feito remotamente (em outra máquina) abrindo assim a opção de um registro centrar para aplicações distribuídas.

Discussão

O padrão Registry é extremamente importante em Orientação a Objetos porque permite que objetos colaborem sem que estejam fisicamente acoplados. A implementação pode ter muitas variantes, mas sob uma forma ou outra é utilizado em muitas tecnologias java como JNDI para encontrar objetos genéricos e Jini e OSGi para encontrar serviços.

Atualmente com o uso de motores de injeção podemos pensar que não ha mais espaço para usar Registry, mas na realidade o motor de injeção usa o padrão Registry para registrar e encontrar todos as classes que precisam ser instanciadas e suas respectivas dependências.

Padrões relacionados

O padrão Registry é utilizando para sempre que uma abstração precisa ser relacionada à implementação de forma desacoplada. Portanto é natural associa-lo ao padrão Service . O Registry é também encontrado junto ao padrão Repository e Bridge.

Porque o registro é global o uso de Registry é uma boa alternativa ao uso de Singleton já que provê a opção de acesso a apenas uma instância sem forçar que a classe seja realmente implementada como um Singleton, efetivamente facilitando o padrão Shared Object.

O padrão Registry também pode substituir o padrão Service Locator em que podemos obter o serviço desejado usando algum tipo de chave ou endereço. E, modernamente, é isto que acontece em um motor de injeção, em que o uso do registro subsitui o uso de localizadores de serviço especificos.

Scroll to Top