Desenvolvimento - Visual Basic .NET

.NET: Creational Pattern - Builder

Há algum tempo já falamos de uma pattern que fazia parte da seção Behavioral (Comportamental), chamada Template Method. Este artigo falará sobre uma outra pattern chamada Builder, que por sua vez encontra-se na seção Creational (Criacional).

por Israel Aéce



Há algum tempo já falamos de uma pattern que fazia parte da seção Behavioral (Comportamental), chamada Template Method. Este artigo falará sobre uma outra pattern chamada Builder, que por sua vez encontra-se na seção Creational (Criacional).

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:

1
2
3
4
5
6
7
8
9
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":

1
2
3
4
5
6
7
8
9
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.

Artigo desenvolvido utilizando:

* Visual Studio .NET 2003
* .NET Framework 1.1
* Windows XP Professional

Clique aqui para fazer Download do Código.
Israel Aéce

Israel Aéce - Especialista em tecnologias de desenvolvimento Microsoft, atua como desenvolvedor de aplicações para o mercado financeiro utilizando a plataforma .NET. Como instrutor Microsoft, leciona sobre o desenvolvimento de aplicações .NET. É palestrante em diversos eventos Microsoft no Brasil e autor de diversos artigos que podem ser lidos a partir de seu site http://www.israelaece.com/. Possui as seguintes credenciais: MVP (Connected System Developer), MCP, MCAD, MCTS (Web, Windows, Distributed, ASP.NET 3.5, ADO.NET 3.5, Windows Forms 3.5 e WCF), MCPD (Web, Windows, Enterprise, ASP.NET 3.5 e Windows 3.5) e MCT.