Builder é um padrão de projeto de software criacional que permite a separação da construção de um objeto complexo da sua representação, de forma que o mesmo processo de construção possa criar diferentes representações.

Estrutura

editar
 
Diagrama UML da estrutura do padrão Builder

O padrão Builder, da forma como foi descrito no livro Design Patterns: Elements of Reusable Object-Oriented Software, contém os seguintes elementos:

  • director — constrói um objeto utilizando a interface do builder;
  • builder — especifica uma interface para um construtor de partes do objeto-produto;
  • concrete builder — define uma implementação da interface builder, mantém a representação que cria e fornece interface para recuperação do produto;
  • product — o objeto complexo acabado de construir. Inclui classes que definem as partes constituintes.

Utilização

editar

O padrão Builder pode ser utilizado em uma aplicação que converte o formato de texto RTF para uma série de outros formatos e que permite a inclusão de suporte para conversão para outros formatos, sem a alteração do código fonte do leitor de RTF.

A implementação da solução para esse problema pode ser realizada através de uma classe de leitura (director) associada a uma classe capaz de converter o formato RTF para outra representação (builder). O objeto da classe de leitura lê cada token do texto e executa o método apropriado no objeto de conversão, de acordo com tipo do token. A classe de conversão possui um método para cada tipo de token, incluindo os caracteres comuns, parágrafos, fontes e etc. Para cada formato de texto suportado é criada uma classe de conversão especializada (concrete builder). Um conversor para formato ASCII, por exemplo, poderia ignorar qualquer requisição para converter tokens que não fossem caracteres comuns. Um conversor para o formato PDF, por outro lado, iria processar qualquer requisição para poder converter o estilo, além do texto.

Vantagens

editar
  • Permite variar a representação interna de um produto;
  • Encapsula o código entre construção e representação;
  • Provê controle durante o processo de construção.

Desvantagens

editar
  • Requer criar um concrete builder específico para cada instância diferente do produto.

Comparação com o Abstract Factory

editar

O padrão Builder é muitas vezes comparado com o padrão Abstract Factory pois ambos podem ser utilizados para a construção de objetos complexos. A principal diferença entre eles é que o Builder constrói objetos complexos passo a passo e procura evitar ser um anti-padrão, enquanto o Abstract Factory constrói famílias de objetos, simples ou complexos, de uma só vez - e permite polimorfismo.

Exemplo

editar

Neste exemplo, o método lerRTF() (da classe LeitorRTF) percorre uma lista com os tokens encontrados no texto de entrada (formato RTF) e, para cada tipo de token, chama um método do objeto de tipo ConversorTexto. Dependendo do formato escolhido para o texto de destino, será escolhida uma implementação da classe ConversorTexto: ConversorPDF, ConversorTeX ou ConversorASCII. Cada uma destas classes implementa os métodos de acordo com as características do formato relacionado.

Note que a classe ConversorASCII não implementa os métodos converteParagrafo() nem converteFonte() porque o formato ASCII não possui elementos de estilo.

Diagrama

editar
 
Exemplo de Diagrama em UML para o Padrão Builder.

Código

editar

Este código, escrito na linguagem Java, mostra a implementação do diagrama mostrado acima.

 abstract class ConversorTexto {
 	public void converterCaractere(char c) {
 		// vazio
 	}

 	public void converterParagrafo() {
 		// vazio
 	}

 	public void converterFonte(Fonte f) {
 		// vazio
 	}
 }

 class ConversorPDF extends ConversorTexto {
 	public void converterCaractere(char c) {
 		System.out.print("Caractere PDF");
 	}

 	public void converterParagrafo() {
 		System.out.print("Parágrafo PDF");
 	}

 	public void converterFonte(Fonte f) {
 		System.out.print("Fonte PDF");
 	}
 }

 class ConversorTeX extends ConversorTexto {
 	public void converterCaractere(char c) {
 		System.out.print("Caractere Tex");
 	}

 	public void converterParagrafo() {
 		System.out.print("Paragrafo Tex");
 	}

 	public void converterFonte(Fonte f) {
 		System.out.print("Fonte Tex");
 	}
 }

 class ConversorASCII extends ConversorTexto {
 	public void converterCaractere(char c) {
 		System.out.print("Caractere ASCII");
 	}
 }

 class LeitorRTF {

 	private ConversorTexto conversor;

 	LeitorRTF(ConversorTexto c) {
 		this.conversor = c;
 	}

 	public void lerRTF() {

 		List<Token> tokens = obterTokensDoTexto();

 		for (Token t : tokens) {
 			if (t.getTipo() == Token.Tipo.CARACTERE) {
 				conversor.converterCaractere(t.getCaractere());
 			}
 			if (t.getTipo() == Token.Tipo.PARAGRAFO) {
 				conversor.converterParagrafo();
 			}
 			if (t.getTipo() == Token.Tipo.FONTE) {
 				conversor.converterFonte(t.getFonte());
 			}
 		}
 	}
 }

 public class Cliente {

 	public static void main(String[] args) {

 		ConversorTexto conversor;
 		if (args[0].equals("pdf")) {
 			conversor = new ConversorPDF();
 		} else if (args[0].equals("tex")) {
 			conversor = new ConversorTeX();
 		} else {
 			conversor = new ConversorASCII();
 		}
 		LeitorRTF leitor = new LeitorRTF(conversor);
 		
 		leitor.lerRTF();
 	}
 }

A classe Cliente determina, através do parâmetro passado ao programa Java ("pdf" para formato PDF, "tex" para Tex e qualquer outro para ASCII), qual das classes derivadas de ConversorTexto irá utilizar na construção da classe LeitorRTF.

Lista de Padrões Criacionais

editar

Bibliografia

editar