DEV Community

Higor Diego
Higor Diego

Posted on

Padrão - Builder

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.

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); 

Enter fullscreen mode Exit fullscreen mode

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:


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);

Enter fullscreen mode Exit fullscreen mode

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.

Top comments (0)