Padrões de projeto em .NET: Builder

 

A intenção deste padrão é separar a construção de um objeto complexo da sua representação de modo que o mesmo processo de construção possa criar diferentes representações.

 

Como motivação para utilização deste padrão, utilizaremos o exemplo de uma fábrica de persianas. Uma fábrica de persianas vende 3 tipos de produtos: persianas horizontais, persianas verticais e black outs. Cada um destes produtos tem especificações de fabricação diferentes. Por exemplo: uma persiana vertical deve ter suas lâminas fabricadas na posição vertical, além de ser acompanhada, opcionalmente, por um bandô, que fica colocado acima da persiana, cobrindo seu trilho. Além disso, seus comandos devem fazer as lâminas correrem pelo trilho, de uma lado ao outro, ou girá-las 180 graus horizontalmente. No caso da persiana horizontal, não há bandô, suas lâminas são fabricadas em posição horizontal e seus comandos permitem que as lâminas subam ou desçam, ou girem 180 graus na vertical. Quando se trata de um black out, suas lâminas são fabricadas em posição vertical, maiores em largura e seus comandos permitem que as lâminas percorram o trilho de um lado ao outro, porém, não girem. O black out também tem a opção do bandô. Além disso, caso haja a possibilidade de fabricação de uma persiana de especificações diferentes às 3 anteriores, deve ser fácil acrescentar este novo produtor sem afetar o construtor.

 

Uma solução é configurar a classe Fabrica com um objeto Persiana que é responsável por construir os 3 tipos de persianas. À medida que a Fabrica recebe solicitações para a construção de persianas, ele usa o objeto Persiana para realizar esta construção. Os objetos Persiana são responsáveis tanto por construir as persianas quanto por representá-las sob diferentes especificações.

 

As subclasses de Persiana se especializam em diferentes especificações. Por exemplo: um PersianaVertical ignora solicitações de construção de qualquer tipo de persiana, exceto a persiana vertical. Por outro lado, um PersianaHorizontal implementará operações para todas as solicitações visando construir persianas horizontais. Por fim, um BlackOut produzirá um objeto para a construção de black outs.

 

Cada tipo de classe construtora implementa o mecanismo para a criação e montagem de um objeto complexo, colocando-o atrás de uma interface abstrata. O construtor é separado da fábrica, que é responsável pela análise da solicitação de construção de uma persiana.

 

O padrão Builder captura todos estes relacionamentos. Cada classe construtora é chamada um builder no padrão, e o leitor é chamado de director. Aplicado a este exemplo, o Builder separa o algoritmo para interpretar uma solicitação de construção de uma persiana (isto é, a fábrica de persianas) de como a persiana solicitada é construída e representada. Isso nos permite reutilizar o algoritmo de análise (parsing) da Fabrica para criar diferentes persianas – simplesmente configure a Fabrica com diferentes subclasses de Persiana.

 

Quando usar Builder?

Use o padrão Builder quando:

 

  • O algoritmo para criação de um objeto complexo deve ser independente das partes que compõem o objeto e de como elas são montadas;
  • O processo de construção deve permitir diferentes representações para o objeto que é construído

Estrutura

 

netpadbuilderfig01.JPG

 

  • Builder (Persiana): especifica uma interface abstrata para criação de partes de um objeto.
  • BuilderConcreto (PersianaVertical, PersianaHorizontal, BlackOut): constrói e monta partes do objeto pela implementação da interface Builder; define e mantém a representação que cria e fornece uma interface para recuperação do produto (por exemplo, RecuperarPersianaVertical, RecuperarPersianaHorizontal).
  • Director (Fabrica): constrói um objeto usando a interface de Builder.
  • Produto (objetos de PersianaVertical, PersianaHorizontal e BlackOut): representa o objeto complexo em construção; inclui classes que definem as partes constituintes, inclusive as interfaces para a montagem das partes no resultado final.

Colaborações

  • O cliente cria o objeto Director e o configura com o objeto Builder desejado.
  • Director notifica o construtor sempre que uma parte do produto deve ser construída.
  • Builder trata solicitações do diretor e acrescenta partes ao produto.
  • O cliente recupera o produto do construtor.

netpadbuilderfig02.JPG

 

Exemplo de código

Definiremos a função CriarPersiana, que aceita como argumento um construtor (builder) da classe Persiana.

 

A classe IPersiana define a seguinte interface para a construção de persianas:

 

Public Interface IPersiana

 

    Sub AtribuirDimensoes(ByVal pLargura As Integer, _

                          ByVal pAltura As Integer)

    Sub AtribuirCor(ByVal pCor As Color)

    Sub EscolherMaterial(ByVal pMaterial As TiposMaterial)

 

    Function RecuperarPersiana() As IPersiana

 

End Interface

 

Essa interface pode realizar 3 operações: adicionar dimensões a uma persiana, atribuir uma cor a uma persiana e escolher o material que vai ser utilizado na fabricação da persiana. A operação RecuperarPersiana retorna a persiana a persiana para o cliente. As subclasses de Persiana redefinirão essa operação para retornar a persiana que construíram.

 

Dada a interface IPersiana, podemos criar a função CriarPersiana, de forma a aceitar este construtor (builder) como um parâmetro.

 

Como os outros padrões de criação, o padrão Builder encapsula como os objetos são criados. Neste caso, através da interface definida por IPersiana. Isso significa que podemos reutilizar IPersiana para construir diferentes tipos de persianas. A operação CriarPersiana nos dá um exemplo:

 

    Public Function CriarPersiana(ByVal pBuilder As IPersiana) As      

    IPersiana

 

        pBuilder.AtribuirDimensoes(150, 80)

        pBuilder.AtribuirCor(Blue)

        pBuilder.EscolherMaterial(TiposMaterial.Tecido)

 

        Return pBuilder.RecuperarPersiana

 

    End Function

 

Note que IPersiana, por si própria, não cria persianas. Sua finalidade principal é somente definir uma interface para criar persianas. Ela define implementações vazias primariamente por conveniência. Subclasses de IPersiana fazem o trabalho real.

 

Os clientes, então, podem usar a função CriarPersiana em conjunto com um dos objetos instanciados pelas subclasses de IPersiana para criar persianas:

 

    Dim OPersiana As PersianaInfo

    Dim Fabrica As FabricaPersianas

    Dim OBuilder As PersianaVertical

 

    Fabrica.CriarPersiana(OBuilder)

    OPersiana = OBuilder.RecuperarPersiana()

 

No próximo artigo estaremos discutindo outro padrão de criação: o Factory Method.