A pattern Builder tem por finalidade isolar a construção de um objeto complexo da sua representação, levando em consideração que o mesmo processo de construção possa criar diferentes representações. Sendo assim, o algoritmo para a construção de um objeto deve ser independente das partes que realmente compõem o objeto e também de como eles são montados.
Utilizando esta pattern, o que temos a fazer é criar uma classe, qual especifica uma interface abstrata para a criação das partes de um objeto-produto. Esta classe abstrata deverá ser herdada pelos objetos concretos que implementaram os métodos de construção para aquele objeto. Esta classe concreta nos fornecerá uma forma de recuperarmos o produto, retornando-o de alguma forma para o cliente que o solicitou.
Vejamos abaixo os participantes envolvidos nesta pattern:
- Director: Constrói um determinado objeto, utilizando a interface de Builder (classe abstrata).
- Builder: Define uma interface abstrata para a criação das partes de um objeto-produto.
- ConcreteBuilder: Implementa os métodos de construção da classe abstrata e também mantém a representação do objeto que cria. Fornece ao cliente um método para a recuperação do produto.
- Product: Representa o objeto complexo em construção, incluindo as interfacces para a montagem das partes no resultado final.
O diagrama abaixo ilustrará estes participantes:
|

|
| Figura 1 – Participantes da Pattern Builder. |
Antes de começarmos a analisar o código da pattern, vamos primeiramente entender o cenário: Teremos dois tipos de objetos complexos, um chamado “Apartamento” e outro chamado “Casa”, pois cada um desses objetos tem particularidades em sua criação, ou seja, implementam diferentemente os métodos de sua construção. Abaixo a classe ConstrucaoBuilder que define a interface necessária para os objetos concretos:
|
|
|
| Public MustInherit Class ConstrucaoBuilder |
| |
| Protected _dados As Hashtable |
| |
| Public MustOverride Sub ConstroiParedes() |
| Public MustOverride Sub ConstroiJanelas() |
| Public MustOverride Sub DefineNumero() |
| |
| End Class |
|
|
| Código 1 – Classe Base que contém a Interface para a criação dos objetos. |
Confrontando o código acima com o modelo estrutural da pattern, esta classe é a que chamamos de “Builder”, que define a interface abstrata. Depois disso, o que temos à fazer é criar uma classe (“Director”) que terá receberá como parâmetro em um método construtor um objeto do tipo da classe abstrata, e internamente será invocado seus métodos para a construção do objeto. O código abaixo ilustra a classe “Director”:
|
|
|
| Public Class Construtora |
| |
| Public Sub Construir(ByVal construcao As ConstrucaoBuilder) |
| construcao.ConstroiJanelas() |
| construcao.ConstroiParedes() |
| construcao.DefineNumero() |
| End Sub |
| |
| End Class |
|
|
| Código 2 – Classe “Director”. |
Como podemos ver, recebemos no parâmetro do método “Construir” um objeto do tipo “ConstrucaoBuilder”, que é o nosso objeto “Builder”. Podemos ver que internamente são invocados os métodos de criação do objeto, definindo assim uma ordem de criação do objeto que está sendo informado e reutilizando o algoritmo (os passos) de criação para todos os objetos.
Feito isso, nos resta implementarmos os nossos objetos complexos (Casa e Apartamento), que obrigatóriamente devem derivar da classe “ConstrucaoBuilder”, implementando os seus métodos de criação e retorno para o cliente. Abaixo o código relacionado ao nosso objeto “Apartamento”:
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
| 6 |
| 7 |
| 8 |
| 9 |
| 10 |
| 11 |
| 12 |
| 13 |
| 14 |
| 15 |
| 16 |
| 17 |
| 18 |
| 19 |
| 20 |
| 21 |
| 22 |
| 23 |
| 24 |
| 25 |
| 26 |
|
|
| Public Class Apartamento |
| |
| Inherits ConstrucaoBuilder |
| |
| Public Overrides Sub ConstroiJanelas |
| _dados = New Hashtable |
| _dados.Add(“Janelas”, “2”) |
| End Sub |
| |
| Public Overrides Sub ConstroiParedes |
| _dados.Add(“Paredes”, “12”) |
| End Sub |
| |
| Public Overrides Sub DefineNumero |
| _dados.Add(“Número”, “A-56”) |
| End Sub |
| |
| Public Sub VisualizarConstrucao |
| Console.WriteLine(“APARTAMENTO:”) |
| For Each d As DictionaryEntry In _dados |
| Console.WriteLine(“{0}: {1}”, d.Key, d.Value) |
| Next |
| Console.WriteLine() |
| End Sub |
| |
| End Class |
|
|
| Código 3 – Classe Apartamento (“ConcreteBuilder”). |
Vemos que ao herdar a classe “ConstrucaoBuilder” os métodos “ConstroiJanelas”, “ConstroiParedes”, “DefineNumero” e criamos um método chamado “VisualizarConstrucao” para devolver ao cliente o resultado gerado. Por questões de exemplo, a classe “Casa” tem a mesma estrutura interna em seus métodos de construção e sendo assim, vamos ocultá-la aqui por questões de espaço, mas pode consultá-la no código fonte do artigo.
E finalmente, a chamada no cliente fica:
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
| 6 |
| 7 |
| 8 |
| 9 |
| 10 |
| 11 |
| 12 |
| 13 |
|
|
| Sub Main() |
| |
| Dim construtora As New Construtora |
| Dim apto As New Apartamento |
| Dim casa As New Casa |
| |
| construtora.Construir(apto) |
| construtora.Construir(casa) |
| |
| apto.VisualizarConstrucao() |
| casa.VisualizarConstrucao() |
| |
| End Sub |
|
|
| Código 4 – Consumindo as classes no cliente. |
Vemos que criamos/configuramos a instância de uma classe do tipo “Construtora” que é o nosso “Director”, que envia as solicitações ao Builder, que este por sua vez fará o seu trabalho de construção de uma determinada parte do objeto concreto. Criamos também mais dois objetos, sendo um do tipo “Apartamento” e outro do tipo “Casa”, quais são posteriormente passados para o método “Construir” do nosso Director, e este executa os métodos de construção respectivos do objeto em questão.
Pode-se reparar, que independentemente do objeto passado para o método construtor de nosso “Director”, o processo de criação do objeto será executado – baseando-se na instância do mesmo – e assim percebemos que separamos a criação dos objetos complexos da sua representação mas utilizando o mesmo processo, ou melhor, os mesmo passos, possibilitando diferentes representações.
Aplica-se esta pattern quando o algoritmo de criação de um objeto complexo deve ser independente das partes que o compõem das quais são montadas e também quando deverá permitir diferentes representações para o objeto que é construído.
CONCLUSÃO: Apesar de ser uma pattern de utilização 3 em uma escala de 0 à 5, é útil quando necessitamos separar a construção de um objeto complexo da sua representação, criando assim, diversas representações deste objeto.
OOBuilder.zip (17.17 kb)