Submarino.com.br

Adapter

Objetivo

Permitir que um objeto seja utilizado através de um contrato diferente.

Propósito

Adapter (Adaptador) é um padrão de projeto que permite que um objeto seja utilizado com um contrato diferente [1] do seu. O contrato é o conjunto de métodos, parâmetros e funcionalidades públicos.

Muitas vezes você precisa utilizar um objeto de uma classe no lugar de um outro, mas os contratos dos objetos não são compatíveis. Modificar o objeto que você já possui pode não ser possível (porque é de terceiros, por exemplo) ou prático (as regras já implementadas são relativamente complexas).

O padrão propõe que se construa um novo objeto, o Adapter. Este objeto terá a interface que o programa precisa mas ele delegará todos os comandos para um outro objeto que tem um contrato diferente. O Adapter encapsula o objeto que realmente irá realizar o trabalho em uma interface compatível com a que o é esperada. Por este motivo o padrão Adapter é também chamado de Wrapper ('que embrulha').

Implementação

O padrão Adapter pode ser utilizando tanto quando o contrato original é especificada por uma classe java ou por uma interface. É mais fácil quando o contrato é definido por uma interface, porque desta forma você sabe que pode sempre criar um objeto com aquele contrato. Ao trabalhar com classes é mais complexo. Se a classe é final e não pode ser herdada criar um adaptador é impossível apenas usando a linguagem Java e terá que recorrer a bibliotecas avançadas de bytecode rewrite. Vejamos como seria a implementação quando o contrato é baseado em uma interface. Este é o caso mais comum.

Imaginemos que temos um objeto de uma classe chamada BalanceCalculator de um pacote legado que contém um conjunto de regras valioso que não queremos reimplementar. Este objeto tem o seguinte contrato


public class BalanceCalculator {

    // atributos e campos omitidos.
	
	public double calculateBalance(Integer account, Calendar date) {
	   // lógica omitida
	}

}

Código 1:

Queremos usar esta classe em um novo projeto que contém um contrato utilizado pelo sistema para calculo de saldos, contudo o contrato é diferente.


public interface BalanceResolver {
	
	public Money balanceFor(Account account, Date date);

}

Código 2:

O objetivo do padrão Adapter é criar um objeto com este contrato, mas que se utiliza do objeto anterior.


public class BalanceCalculatorAdapter implements  BalanceResolver{
	
	BalanceCalculator original;
	
	public BalanceCalculatorAdapter(BalanceCalculator original, Locale locale){
		this.original = original;
		this.locale = locale;
	}
	
	public Money balanceFor(Account account, Date date) {
	
		Calendar calendar = Calendar.getInstance(locale);
		calendar.setTime(date);
	
		return Money.valueOf(
			original.calculateBalance(account.getId(), calendar),
			Currency.getCurrency(locale)
		)
	
	}

}

Código 3:

Este é um exemplo simplificado. Pode ser necessário adaptar também exceções que o objeto original lança e que o novo não. Pode ser necessário realizar algumas ações extra, como no caso em precisamos do Locale correto para podermos criar o Calendar e o Money.

O importante é que é agora possível utilizar o objeto BalanceCalculator onde for possível usar um BalanceResolver.

Padrões relacionados

O padrão Adapter se relaciona a padrões como Decorator e Proxy e existe alguma semelhança entre as implementações. O padrão mais fácil de confundir com Adapter é 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.

Decorator não visa traduzir contratos mas aumentar o numero de operações possíveis com base num tipo previamente existente. Ou seja, o Decorator cria um contrato que não existia antes por adição a um contrato base.

Adapter comunica apenas com um outro objeto e nunca com um conjunto de objetos. Se isso acontecer 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 lógica de cooperação entre os objetos chamados.

Padrão 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

Referências

[1] Design Patterns: Elements of Reusable Object-Oriented Software

Livro:Design Patterns: Elements of Reusable Object-Oriented Software