Adapter

Objetivo

Permitir que um objeto seja utilizado por outro que espera uma interface diferente. [1].

Interface, aqui, não se refere ao tipo Interface do Java e sim ao contrato que o objeto publica. Ou seja, o conjunto de métodos, parâmetros e funcionalidades públicos. Para evitar confusão de linguagem, chamarei contrato ao conjunto de métodos , parâmetros e funcionalidades que o objeto define e podem ser utilizados por outros objetos.

Propósito

Imagine que você precisa utilizar um objeto, no lugar de um outro que utilizava antes, mas o contrato dele não é diretamente compatível com as instruções do objeto que o utiliza. Você não quer mudar todo o seu programa. Mas sem mudar o programa não pode usar a nova classe.

public interface PersonService {

	 public Optional<Person> retrivePerson(FiscalNumber fiscalNumber);
}

// classe dada
public class ReceitaService {

	public PessoaFisica obtemPessoa(String cpf) {
		....
	}
}


public class NameService {

	private PersonService personService;

	public ClientCode(PersonService personService){
		this.personService = personService;
	}

	public Optional<Sting> retriveName(FiscalNumber fiscalNumber) {
		return this.personService.retrivePerson(fiscalNumber)
			.map(p -> p.getName());
	}
}

Imaginemos que temos nosso sistema com a classe NameService que usa a interface PersonService que tinha sido implementada. Mas agora, compramos uma API da Receita Federal que permite buscar as informações da pessoa. O problema é que este objeto não tem o mesmo contrato que a interface PersonService e não podemos mudar o código por que é uma classe em um jar de terceiros.

O padrão Adapter(Adaptador) vem resolver este problema. O padrão propõe que se construa um novo objeto, o Adapter. Este objeto terá a interface que o objeto cliente espera utilizar mas ele delegará todos os comandos para um outro objeto que tem uma interface diferente.

Implementação

A implementação do padrão Adapter consiste em implementar uma classe intermediária - o adaptador - que tem a interfaces que procuramos e contém uma instância da classe que queremos utilizar.

public class ReceitaServiceAdapter
	implements PersonService // interface que queremos implementar
	{

	private ReceitaService original; // classe que queremos usar

	public ReceitaServiceAdapter(ReceitaService original){
		this.orginal = original;
	}

	public Optional<Person> retrivePerson(FiscalNumber fiscalNumber){
		if (fiscalNumber == null){
			return Optional.empty();
		}

		return Optional.ofNullable(original.obtemPessoa(fiscalNumber.toString()))
			.map(p -> convertToPerson(p));

	}

	private Person convertToPerson(PessoaFisica otherPerson){
		Person person = new Person();

		person.setName(otherPerson.getNome());

		// other sets
		...

		return person;
	}
}

Repare que o objeto adapter tem que realizar algumas operações, verificações e conversões de forma a compatibilizar os argumentos recebidos com os argumentos necessários e os objetos obtidos com os objetos que precisam ser retornados. O código do Adapter pode ser mais ou menos complexos dependendo de quanto desalinhados são os contratos.

Discussão

Padrões associados

Adapter se relaciona a muitos outros padrões pela semelhança entre as implementações. O padrão mais fácil de confundir com Adapter é o padrão Proxy. Enquanto o Adapter visa apenas traduzir contratos entre o cliente e o objeto final o Proxy visa poder interferir entre a chamada do cliente e a execução do objeto real.Normalmente sem, sequer, alterar o contrato no caminho.

O padrão Decorator, também conhecido como Wrapper, é um tipo especial de Adapter. Ele não visa traduzir contratos mas sim aumentar o numero de operações possíveis com base num tipo previamente existente. Ou seja, o Decorator adiciona um contrato que não existia antes a um que existia. Na API do Java SE as classes filhas de Number , Character e Boolean são Decorator de tipos primitivos. Obviamente as interfaces são diferentes já que as classes Decorator adicionam novas operações uteis não disponiveis no contrato dos tipos primitivos correspondentes.

O padrão Adaptor comunica apenas com um outro objeto e nunca com um conjunto de objetos. Nesse caso estaremos na presença de um Façade que visa simplificar a utilização de um conjunto de objetos encapsulando as operações mais comuns com esses objetos. Embora esteja sendo feita uma tradução de contratos, Façade vai um pouco mais além introduzindo uma logica de cooperação entre os objetos chamados.

A tabela a seguir tentar resumir as relações

Mapeia Contratos

Altera Contrato

Adiciona lógica

Comunica com mais que um objeto

Adapter

x

Decorator

x

x

Proxy

x

x

Façade

x

x

x

x

Bibliografia

[1] Ralph Johnson, Erich Gamma, John Vlissides, Richard Helm Design Patterns: Elements of Reusable Object-Oriented Software: Addison-Wesley (2005)

Scroll to Top