Padrão - Builder
Published: 2023-01-13 20:33:32

O padrão _Builder_ foi originalmente descrito por Gamma et al. em seu livro "Design Patterns: Elements of Reusable Object-Oriented Software" (1994). Nele, os autores apresentam o padrão _Builder_ como uma maneira de separar a construção de um objeto complexo de sua representação, de modo que o mesmo processo de construção possa criar diferentes representações. 

O padrão _Builder_ é um padrão de criação que se concentra em separar a construção de um objeto complexo de sua representação, de modo que o mesmo processo de construção possa criar diferentes representações. Ele permite que você construa objetos passo a passo, adicionando diferentes partes ou características a eles ao longo do tempo.

Em geral, o _Builder_ é usado quando se quer criar objetos complexos que possuem muitas partes ou configurações diferentes e que são construídos através de vários passos. O _Builder_ fornece uma interface para especificar esses passos e adicionar as partes ou características apropriadas ao objeto.

Existem duas principais partes envolvidas no padrão _Builder_, que são:

- **O Builder**: que é uma interface para especificar os passos para criar o objeto complexo. Ele define os métodos para adicionar as diferentes partes ou características do objeto.
- **O Director**: que é o objeto que controla o processo de construção usando o _Builder_ especificado. Ele pode criar vários tipos de objetos diferentes usando a mesma sequência de passos, mas com diferentes partes ou características.

Há várias vantagens em usar o padrão _Builder_ em seu código, que são:

- **Encapsulamento**: o padrão _Builder_ permite que você esconda a lógica de construção de um objeto complexo dentro do _Builder_ e do Director, em vez de expô-lo diretamente ao cliente. Isso torna o código mais fácil de entender e manter.
- **Flexibilidade**: o padrão _Builder_ permite que você crie diferentes representações de um objeto complexo usando a mesma sequência de passos. Isso significa que você pode criar novas representações sem afetar o código existente.
- **Reutilização**: o padrão _Builder_ permite que você reutilize a lógica de construção de um objeto complexo em diferentes contextos. Isso significa que você pode construir objetos semelhantes usando a mesma lógica de construção.
- **Clareza**: o padrão _Builder_ torna o código mais claro e organizado, pois separa a lógica de construção da lógica do sistema. Isso significa que você pode entender facilmente como um objeto é construído e como ele é usado.
- **Simplicidade**: O padrão _Builder_ simplifica a construção de objetos complexos, pois fornece uma forma organizada de adicionar diferentes partes ou características a um objeto ao longo do tempo.
- **Código limpo**: Ao dividir a construção de um objeto complexo em passos, ele pode tornar o código mais limpo e mais fácil de manter, pois cada passo é isolado e mais fácil de entender.

Segue abaixo um simples exemplo de código usando o padrão _Builder_.

```js
class SandwichBuilder {
    constructor() {
        this.sandwich = new Sandwich();
    }
    
    addBread() {
        this.sandwich.hasBread = true;
    }
    
    addCheese() {
        this.sandwich.hasCheese = true;
    }
    
    addLettuce() {
        this.sandwich.hasLettuce = true;
    }
    
    addMeat() {
        this.sandwich.hasMeat = true;
    }
    
    getSandwich() {
        return this.sandwich;
    }
}

class Sandwich {
    constructor() {
        this.hasBread = false;
        this.hasCheese = false;
        this.hasLettuce = false;
        this.hasMeat = false;
    }
}

class SandwichMaker {
    constructor() {
        this.builder = null;
    }
    
    setBuilder(builder) {
        this.builder = builder;
    }
    
    makeSandwich() {
        this.builder.addBread();
        this.builder.addCheese();
        this.builder.addLettuce();
        this.builder.addMeat();
    }
}

const sandwichBuilder = new SandwichBuilder();
const sandwichMaker = new SandwichMaker();

sandwichMaker.setBuilder(sandwichBuilder);
sandwichMaker.makeSandwich();

const mySandwich = sandwichBuilder.getSandwich();
console.log(mySandwich); 

```

A classe _SandwichBuilder_ é responsável por construir uma instância da classe _Sandwich_ adicionando diferentes partes. Ela tem métodos para adicionar pão, queijo, alface e carne e um método "getSandwich" que retorna o objeto sandwich construído.

A classe _Sandwich_ é uma classe modelo que representa o objeto sandwich. O construtor inicia o objeto com todos os seus atributos como false, e os métodos de adição do sandwichBuilder irão alterar os valores.

A classe _SandwichMaker_ é responsável por usar o objeto _SandwichBuilder_ e fazer o sanduíche, é um objeto que controla o processo de construção usando o Builder especificado. A classe tem método para setar um Builder _(sandwichBuilder)_ e outro método para fazer o sandwich(makeSandwich).

Por fim iniciamos uma nova instância da classe _SandwichBuilder_ chamada _sandwichBuilder_. Em seguida, criamos uma nova instância da classe _SandwichMaker_ chamada _sandwichMaker_.

Depois disso, configuramos o _sandwichMaker_ para usar o _sandwichBuilder_ especificado com o método _setBuilder(sandwichBuilder)_. Isso significa que a classe _SandwichMaker_ usará o _sandwichBuilder_ para construir o sandwich.

Finalmente, usamos o método _makeSandwich()_ do _sandwichMaker_ para construir o sandwich e armazenamos o resultado na variável _mySandwich_. Por fim, usamos o console.log para imprimir o sanduíche construído na tela. O resultado seria um objeto sandwich com todos os seus atributos como true.

_Simples, né?_

Imagine outro cenário na qual a sua gestora de equipe informou que há uma necessidade de consumo de uma API de cep para preenhcimento automático do endereço do usuário no formulário HTML.

Para resolver a seguinte problemática segue o exemplo abaixo:


```js

class AddressBuilder {

    constructor() {
        this.address = {};
    }

    addCEP(cep) {
        this.address.cep = cep;
    }

    addState(state) {
        this.address.state = state;
    }

    addCity(city) {
        this.address.city = city;
    }

    addStreet(street) {
        this.address.street = street;
    }

    getAddress() {
        return this.address;
    }
}

class CepFetcher {
    static url = 'https://brasilapi.com.br/api/cep/v1'
    constructor(builder) {
        this.builder = builder;
    }

    async fetchData(cep) {
        const { cep, state, city, street } = await fetch(`${url}/${this.cep}`).then(response => response.json())
        const data = { cep, state,  city, street };

        this.builder.addCEP(data.cep);
        this.builder.addState(data.state);
        this.builder.addCity(data.city);
        this.builder.addStreet(data.street);
    }
}

const builder = new AddressBuilder();
const fetcher = new CepFetcher(builder);
fetcher.fetchData('01001000');
const address = builder.getAddress();
console.log(address);

```

A classe _AddressBuilder_ é responsável por construir o objeto endereço. Ele tem um método construtor vazio que cria um objeto endereço vazio. Ele também tem métodos para adicionar CEP, Estado, Cidade e Rua à estrutura de dados e um método _getAddress()_ que retorna o objeto endereço completo.

A classe _CepFetcher_ é usada para obter informações de endereço a partir de uma API de CEP usando a URL da API. Ele tem um método construtor que recebe uma instância de _AddressBuilder_ e um método _fetchData()_ que usa o CEP fornecido para obter os dados da API usando o fetch() . Ele então desestrutura a resposta da API para extrair os dados de CEP, estado, cidade e rua. Esses dados são então passados para os métodos correspondentes da classe _AddressBuilder_ para adicioná-los à estrutura de dados. Por fim, o metodo _fetchData_ retorna o objeto endereço completo ao ser chamado o metodo _getAddress()_.

Existe algumas situações comuns que o padrão Builder é útil, que são:

- Quando você precisa construir objetos com muitos atributos opcionais ou variáveis, o padrão _Builder_ pode ajudá-lo a manter a clareza e a simplicidade do código, permitindo que você construa objetos passo a passo.
- Quando você precisa construir objetos complexos que requerem várias etapas ou regras específicas de construção, o padrão _Builder_ permite que você encapsule essa lógica e a reutilize facilmente.
- Quando você precisa construir objetos que representam estruturas de dados hierárquicas, o padrão _Builder_ pode ajudá-lo a organizar a construção de objetos em etapas lógicas.
- Quando você precisa construir objetos que podem ser modificados dinamicamente, o padrão _Builder_ permite que você adicione ou remova elementos de um objeto facilmente.
- Quando você precisa criar objetos que consomem dados de uma api, o pattern builder pode ajuda a organizar e manter a lógica de construção de objetos consistente com os dados retornados pela api.


**Conclusão**

O padrão _Builder_ permite manter a clareza e a simplicidade do código, principalmente quando se trabalha com objetos complexos com muitos atributos opcionais ou variáveis. 

O _Builder_ pode ser útil para várias situações, algumas delas incluem:


- Quando você precisa construir objetos complexos que requerem várias etapas ou regras específicas de construção, o padrão Builder permite que você encapsule essa lógica e a reutilize facilmente.
- Quando você precisa construir objetos que podem ser modificados dinamicamente, o padrão Builder permite que você adicione ou remova elementos de um objeto facilmente.
- Quando você precisa criar objetos que consomem dados de uma API, o padrão Builder pode ajudá-lo a organizar e manter a lógica de construção de objetos consistente com os dados retornados pela API.
- Quando você precisa construir objetos a partir de diferentes tipos de fontes de dados (arquivos, api, base de dados) e precisa manter a lógica de construção consistente, pattern builder pode ser uma ótima escolha.


Espero ter ajudado, até a próxima.