Builder
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
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
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
- 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
- Requer criar um concrete builder específico para cada instância diferente do produto.
Comparação com o Abstract Factory
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
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
Código
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
- Abstract Factory
- Factory Method
- Prototype
- Singleton
Bibliografia
- Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides (1995). Design Patterns. Elements of Reusable Object-Oriented Software 1 ed. Estados Unidos da América: Addison-Wesley. ISBN 0-201-63361-2 !CS1 manut: Nomes múltiplos: lista de autores (link)