Desvendando os mistérios do GoF...
" A
ciência dos projetos consiste em prever as dificuldades de execução. "
Vauvenargues , Luc de Clapiers
Olá pessoal.
Como o abordado no artigo anterior(//www.devmedia.com.br/articles/viewcomp.asp?comp=14713),
estaremos iniciando nossos estudos nos padrões de projeto segundo o GoF.
Hoje vamos discutir sobre o padrão de projeto Builder.
A intenção do padrão Construtor(Builder), é separar a construção
de um objeto complexo, de modo que o mesmo processo de construção possa criar
várias representações diferentes.
A classe Builder
representada no diagrama acima é apenas uma interface abstrata, isto é, ela
introduz uma forma padrão para se criar cada um dos passos necessários para a
construção do objeto final. Essa interface tem necessariamente que ser
implementada por uma ou mais classes do tipo ConcreteBuilder, que são as responsáveis por criar instâncias de
passos isolados.
Devemos, então, implementar classes ConcreteBuilder diferentes para representar
cada vertente de atividade possível, com cada uma criando apenas os registros extras
necessários para a própria vertente envolvida.
A classe Director
do diagrama é responsável por juntar as partes, ou seja, é ela quem constrói o
objeto final, chamando na ordem correta as funções que constroem cada passo
separado. O Director recebe como
parâmetro a instância de um ConcreteBuilder
e usa esta instância para gerenciar a criação dos passos.
“Pela forma como opera, é comum
que o padrão Builder esteja associado a outros padrões criacionais. Por
exemplo, usar uma Abstract Factory para determinar qual a classe
ConcreteBuilder que deve ser usada pelo Director ou Singleton para garantir que
haja no máximo apenas uma instância de cada ConcreteBuilder. Mas isso fica para
outro momento.”
Vamos iniciar nosso exemplo criando um projeto do tipo Console Application e lhe dando o nome de Builder. Agora vamos adicionar uma nova pasta com o nome de Model e adicione uma classe com o nome Montadora. Sua solução deve ficar como na figura 1.
Figura 1.
Nosso primeiro passo será a criação do “Product” que neste caso será um
veículo. Abra a Classe Montadora modifique sua namespace para Model e inclua a
Listagem 1 como uma classe deste namespace.
/// <summary> /// Produto /// </summary> public class Veiculo { //
Configura o tipo do Veículo private
string tipo; // Criamos
uma Hashtable para armazenar as partes do veículo atribuindo a elas uma
chave. // Assim podemos
realizar buscas nos elementos da coleção. private Hashtable partes = new Hashtable(); // Construtor da classe. public
Veiculo(string tipo) { this.tipo
= tipo; } // Crio um
Indexador para a classe public object this[string chave] { get
{ return partes[chave]; } set
{ partes[chave] = value; } } /// <summary> /// Método responsável por imprimir os
dados do Veículo /// </summary> public
void Mostra() { Console.WriteLine("\n-----------------------------------------------------"); Console.WriteLine("Tipo
do Veículo: {0}", tipo); Console.WriteLine("Chassi : {0}", partes["chassi"]); Console.WriteLine("Motor : {0}", partes["motor"]); Console.WriteLine("Rodas : {0}", partes["rodas"]); Console.WriteLine("Portas : {0}", partes["portas"]); Console.Read(); } } |
Listagem 1 |
O próximo passo é criação do Abstract Builder como na
listagem 2.
A classe ConstruirVeiculo é o Abstract Builder, ou
seja, ela apenas diz quais são os métodos que um Builder deve ter.Por ser
abstrata, esta classe não pode ser instanciada. É preciso criar as heranças
concretas que implementarão as funções introduzidas na super classe.
/// <summary> /// Abstract Builder /// </summary> public abstract class ConstruirVeiculo { // Crio um
veículo protected
Veiculo veiculo; // Crio uma
Propriedade public
Veiculo Veiculo { //
Busco o veículo get
{ return veiculo; } } public
abstract void
ContruirChassi(); public
abstract void
ConstruirMotor(); public
abstract void
ConstruirRodas(); public
abstract void
ConstruirPortas(); } |
Listagem 2 |
Estas classes que herdam da Abstract Builder são
denominadas de Concrete Builder.Cada classe concreta dessas é responsável por
criar as etapas corretas do objeto a qual se referem. Depois de ter o Builder
correto criado, é responsabilidade da Director montar o produto, que é o objeto
final.
Nossas classes Abstract Builder estão descritas na
listagem 3.
/// <summary> /// Concret Builder - Construtor concreto 1. /// Constroi um veículo do tipo Moto /// </summary> class ConstrutorMoto : ConstruirVeiculo { public
override void
ContruirChassi() { veiculo = new Veiculo("Moto"); veiculo["chassi"]
= "Chassi da Moto"; } public
override void
ConstruirMotor() { veiculo["motor"]
= "500 cc"; } public
override void
ConstruirRodas() { veiculo["rodas"]
= "2"; } public
override void
ConstruirPortas() { veiculo["portas"]
= "0"; } } /// <summary> /// Concret Builder - Construtor concreto 2. /// Constroi um veículo do tipo Carro /// </summary> class ConstrutorCarro : ConstruirVeiculo { public
override void
ContruirChassi() { veiculo = new Veiculo("Carro"); veiculo["chassi"]
= "Chassi do Carro"; } public
override void
ConstruirMotor() { veiculo["motor"]
= "2500cc"; } public
override void
ConstruirRodas() { veiculo["rodas"]
= "4"; } public
override void
ConstruirPortas() { veiculo["portas"]
= "4"; } } |
Listagem 3 |
Chegou a hora de implementarmos o Director. Listagem
4.
/// <summary> /// Director - Conecta as parter produzidas /// <remarks> /// A
Montadora usa a ConstruirVeiculo para construir uma variedade de Veiculo /// em uma
série de passos sequenciais. /// </remarks> /// </summary> public class Montadora { /// <summary> /// Para todos os objetos da estrutura. /// </summary> /// <param
name="construirVeiculo"></param> public
void Construir(ConstruirVeiculo
construirVeiculo) {
construirVeiculo.ContruirChassi();
construirVeiculo.ConstruirRodas();
construirVeiculo.ConstruirPortas(); construirVeiculo.ConstruirMotor(); } } |
Listagem 4 |
Após nosso modelo já pronto, vamos à classe Program.
Aqui nós iremos consumir a classe Montadora e criaremos um Carro e uma Moto.
using System; using System.Collections.Generic; using System.Linq; using System.Text; using Model; namespace Builder { /// <summary> /// Separa a construção de um objeto complexo da sua
representação de forma que o mesmo processo /// de construção possa criar representações diferentes. /// </summary> class Program { static
void Main(string[]
args) { // Cria
a montadora com construtores de veículos Montadora
montadora = new Montadora(); //
Build Moto ConstruirVeiculo
cMoto = new ConstrutorMoto(); //
Build Carro ConstruirVeiculo
cCarro = new ConstrutorCarro(); //
Construir e exibir os veículos montadora.Construir(cMoto); cMoto.Veiculo.Mostra(); montadora.Construir(cCarro); cCarro.Veiculo.Mostra(); } } } |
Listagem 5 |
Use o Padrão Builder quando:
·
O
algoritmo para criar um objeto complexo deve ser independente das partes que
constroem o objeto e de como elas são montadas.
·
O
processo de construção necessita fornecer representações diferentes para o
objeto que é construído.
Conseqüências do Padrão Builder:
·
Permite
variar a representação interna de um produto;
·
Isola
os códigos de construção e representação;
·
Permite
controle fino sobre o precesso de construção.
O Builder permite
variar a representação interna do produto que ele cria. Ele também esconde os
detalhes de como o produto é montado. Cada Builder específico é independente de
outros e do resto do programa. Isso melhora a modularidade e faz a adição de
outros Builders relativamente simples. Como cada Builder constrói o produto
final passo-a-passo, dependendo dos dados, o programador tem mais controle
sobre o produto final construído.
No próximo artigo continuaremos abordando os padrões
de projeto com foco no C#.
Qualquer dúvida podem me mandar por email.
http://twitter.com/vitormeriat