Desenvolvimento - C#

Desing Patterns na prática - Desvendando o Builder (parte 2)

Neste artigo 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.

por Vitor Meriat



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(http://www.linhadecodigo.com.br/Artigo.aspx?id=2573), 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.

Antes de implementarmos nosso exemplo, temos de conhecer a nomenclatura deste padrão de projeto conforme o diagrama abaixo.

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.

vitormeriat@gmail.com

http://twitter.com/vitormeriat

Até a próxima!!!

Vitor Meriat

Vitor Meriat - Cusando a faculdade de Bacharel em Sistemas da Informação, programador .NET há dois anos, trabalha atualmente na Corretora Seguros BRB em Brasília com a plataforma .Net e Arquitetura da Informação.