Mudanças entre as edições de "Padrões de Projetos - Builder"

De Aulas
(Criou página com ' Afluentes: Modelos, métodos e técnicas da engenharia de software = Definição = O padrão de projeto Builder (ou Construtor em português) é um padrão criacional qu...')
 
Linha 1: Linha 1:
 +
  
 
Afluentes: [[Modelos, métodos e técnicas da engenharia de software]]
 
Afluentes: [[Modelos, métodos e técnicas da engenharia de software]]
Linha 22: Linha 23:
  
 
== Exemplo em Java ==
 
== Exemplo em Java ==
Imagine que estamos criando uma classe Carro que tem vários parâmetros opcionais, como modelo, ano, motor e cor. Em vez de ter um construtor com muitos parâmetros, podemos usar o padrão Builder para facilitar a construção do objeto.
+
Vamos pegar nosso exemplo que já trabalhamos antes, uma classe <code>Enemy</code> para os inimigos em um jogo digital. Essa classe vários parâmetros opcionais, como posição x e y, pontos de experiência inicial (xp) e pontos de vida (hp). Em vez de ter um construtor com muitos parâmetros, podemos usar o padrão Builder para facilitar a construção do objeto.
  
Exemplo de um construtor de Carro:<syntaxhighlight lang="java">
+
=== Nossa classe Enemy com builder ===
// Produto: o objeto final que será construído
+
<syntaxhighlight lang="java">
class Carro {
+
public class Enemy {
     private String modelo;
+
    private int id; // id do inimigo no jogo
     private String cor;
+
     private int x; // posição x do inimigo
     private int ano;
+
     private int y; // posição y do inimigo
     private String motor;
+
     private int xp; // pontos de experiência
 +
     private int hp; // pontos de vida
  
    // Construtor privado para forçar a criação via Builder
+
     private static int counter = 0;
     private Carro(CarroBuilder builder) {
 
        this.modelo = builder.modelo;
 
        this.cor = builder.cor;
 
        this.ano = builder.ano;
 
        this.motor = builder.motor;
 
    }
 
  
     @Override
+
     // Consrutor privado para forçar a criação via Builder
     public String toString() {
+
     private Enemy(EnemyBuilder builder) {
         return "Carro [modelo=" + modelo + ", cor=" + cor + ", ano=" + ano + ", motor=" + motor + "]";
+
         this.id = Enemy.counter++;
 +
        this.x = builder.x;
 +
        this.y = builder.y;
 +
        this.xp = builder.xp;
 +
        this.hp = builder.hp;
 
     }
 
     }
  
    // Classe estática Builder
+
     public static class EnemyBuilder {
     public static class CarroBuilder {
+
         private int x;
         private String modelo;
+
         private int y;
         private String cor;
+
         private int xp;
         private int ano;
+
         private int hp;
         private String motor;
 
  
        // Métodos de configuração do Builder
+
         public EnemyBuilder setPosition(int x, int y) {
         public CarroBuilder setModelo(String modelo) {
+
             this.x = x;
             this.modelo = modelo;
+
            this.y = y;
 
             return this;
 
             return this;
 
         }
 
         }
  
         public CarroBuilder setCor(String cor) {
+
         public EnemyBuilder setXp(int xp) {
             this.cor = cor;
+
             this.xp = xp;
 
             return this;
 
             return this;
 
         }
 
         }
  
         public CarroBuilder setAno(int ano) {
+
         public EnemyBuilder setHp(int hp) {
             this.ano = ano;
+
             this.hp = hp;
 
             return this;
 
             return this;
 
         }
 
         }
  
         public CarroBuilder setMotor(String motor) {
+
         public Enemy build() {
            this.motor = motor;
+
             return new Enemy(this);
             return this;
 
 
         }
 
         }
 +
    }
  
        // Método de construção que retorna o objeto final
+
    public void draw() {
        public Carro build() {
+
        System.out.println("Enemy " + id + " at (" + x + ", " + y + "): XP: " + xp + ", HP:" + hp);
            return new Carro(this);
 
        }
 
 
     }
 
     }
 
}
 
}
 +
</syntaxhighlight>
  
public class BuilderPatternDemo {
+
=== Nossa classe principal que utiliza o builder ===
 +
<syntaxhighlight lang="java">
 +
public class Main {
 
     public static void main(String[] args) {
 
     public static void main(String[] args) {
         // Usando o Builder para construir um objeto Carro
+
         // Criando um objeto do tipo Enemy
         Carro carro = new Carro.CarroBuilder()
+
         Enemy enemy = new Enemy.EnemyBuilder()
                            .setModelo("SUV")
+
                .setPosition(100, 200)
                            .setCor("Preto")
+
                .setXp(34)
                            .setAno(2023)
+
                .setHp(100)
                            .setMotor("V8")
+
                .build();
                            .build();
+
         enemy.draw();
 
 
         System.out.println(carro);
 
 
     }
 
     }
 
}
 
}
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
 
== Explicação ==
 
== Explicação ==
  
# '''Produto (<code>Carro</code>)''': A classe <code>Carro</code> é o objeto que será construído. Ela tem muitos atributos opcionais (modelo, cor, ano, motor). O construtor de <code>Carro</code> é privado para garantir que ele só possa ser criado pelo <code>CarroBuilder</code>.
+
# '''Produto (Enemy)''': A classe Enemy é o objeto que será construído. Ela tem muitos atributos opcionais (posição, pontos de experiência e pontos de vida). O construtor de Enemy é privado para garantir que ele só possa ser criado pelo <code>EnemyBuilder</code>.
# '''Builder (<code>CarroBuilder</code>)''': A classe interna <code>CarroBuilder</code> tem métodos para configurar cada atributo do <code>Carro</code>. Esses métodos retornam o próprio builder (com <code>return this;</code>), permitindo encadear chamadas (técnica chamada de '''fluent interface''').
+
# '''Builder (<code>EnemyBuilder</code>)''': A classe interna <code>EnemyBuilder</code> tem métodos para configurar cada atributo do Enemy. Esses métodos retornam o próprio builder (com <code>return this;</code>), permitindo encadear chamadas (técnica chamada de '''fluent interface''').
# '''Método <code>build()</code>''': O método <code>build()</code> no <code>CarroBuilder</code> é o responsável por criar o objeto <code>Carro</code> final, passando o <code>builder</code> como argumento para o construtor privado de <code>Carro</code>.
+
# '''Método <code>build()</code>''': O método <code>build()</code> no <code>EnemyBuilder</code> é o responsável por criar o objeto Enemy final, passando o <code>builder</code> como argumento para o construtor privado de Enemy.
# '''Cliente''': O código no <code>main</code> demonstra como usar o <code>CarroBuilder</code> para configurar um objeto <code>Carro</code> e depois construí-lo.
+
# '''Cliente''': O código no <code>main</code> demonstra como usar o <code>EnemyBuilder</code> para configurar um objeto Enemy e depois construí-lo.
  
 
== Vantagens do Builder ==
 
== Vantagens do Builder ==

Edição das 09h32min de 10 de outubro de 2024


Afluentes: Modelos, métodos e técnicas da engenharia de software

Definição

O padrão de projeto Builder (ou Construtor em português) é um padrão criacional que separa a construção de um objeto complexo de sua representação final. Ele permite que o mesmo processo de construção crie diferentes representações do objeto, facilitando a criação de objetos com muitas opções ou parâmetros, sem sobrecarregar o construtor com muitos argumentos.

Objetivo

O principal objetivo do Builder é fornecer uma maneira flexível e controlada de criar objetos complexos, onde o processo de criação pode ser dividido em etapas, cada uma configurando uma parte específica do objeto. Isso é particularmente útil para objetos que têm muitos atributos opcionais ou para situações em que a criação envolve um processo complicado.

Componentes principais

  • Builder (Construtor): Define uma interface que descreve como construir as diferentes partes de um objeto complexo.
  • ConcreteBuilder (Construtor Concreto): Implementa a interface Builder e constrói as partes específicas do produto.
  • Product (Produto): O objeto final que será construído.
  • Director (Diretor): Opcionalmente, o Director é responsável por gerenciar o processo de construção e garantir que as diferentes partes do objeto sejam criadas em uma ordem específica.

Quando usar o Builder

  • Quando a criação de um objeto é complicada e envolve muitos parâmetros opcionais.
  • Quando o objeto é imutável, mas tem muitas configurações que precisam ser definidas no momento da construção.
  • Quando há várias representações possíveis de um objeto (por exemplo, diferentes variações do mesmo tipo de produto).

Exemplo em Java

Vamos pegar nosso exemplo que já trabalhamos antes, uma classe Enemy para os inimigos em um jogo digital. Essa classe vários parâmetros opcionais, como posição x e y, pontos de experiência inicial (xp) e pontos de vida (hp). Em vez de ter um construtor com muitos parâmetros, podemos usar o padrão Builder para facilitar a construção do objeto.

Nossa classe Enemy com builder

public class Enemy {
    private int id; // id do inimigo no jogo
    private int x; // posição x do inimigo
    private int y; // posição y do inimigo
    private int xp; // pontos de experiência
    private int hp; // pontos de vida

    private static int counter = 0;

    // Consrutor privado para forçar a criação via Builder
    private Enemy(EnemyBuilder builder) {
        this.id = Enemy.counter++;
        this.x = builder.x;
        this.y = builder.y;
        this.xp = builder.xp;
        this.hp = builder.hp;
    }

    public static class EnemyBuilder {
        private int x;
        private int y;
        private int xp;
        private int hp;

        public EnemyBuilder setPosition(int x, int y) {
            this.x = x;
            this.y = y;
            return this;
        }

        public EnemyBuilder setXp(int xp) {
            this.xp = xp;
            return this;
        }

        public EnemyBuilder setHp(int hp) {
            this.hp = hp;
            return this;
        }

        public Enemy build() {
            return new Enemy(this);
        }
    }

    public void draw() {
        System.out.println("Enemy " + id + " at (" + x + ", " + y + "): XP: " + xp + ", HP:" + hp);
    }
}

Nossa classe principal que utiliza o builder

public class Main {
    public static void main(String[] args) {
        // Criando um objeto do tipo Enemy
        Enemy enemy = new Enemy.EnemyBuilder()
                .setPosition(100, 200)
                .setXp(34)
                .setHp(100)
                .build();
        enemy.draw();
    }
}

Explicação

  1. Produto (Enemy): A classe Enemy é o objeto que será construído. Ela tem muitos atributos opcionais (posição, pontos de experiência e pontos de vida). O construtor de Enemy é privado para garantir que ele só possa ser criado pelo EnemyBuilder.
  2. Builder (EnemyBuilder): A classe interna EnemyBuilder tem métodos para configurar cada atributo do Enemy. Esses métodos retornam o próprio builder (com return this;), permitindo encadear chamadas (técnica chamada de fluent interface).
  3. Método build(): O método build() no EnemyBuilder é o responsável por criar o objeto Enemy final, passando o builder como argumento para o construtor privado de Enemy.
  4. Cliente: O código no main demonstra como usar o EnemyBuilder para configurar um objeto Enemy e depois construí-lo.

Vantagens do Builder

  • Código mais legível: Permite a criação de objetos complexos com código que é mais fácil de entender, especialmente quando há muitos parâmetros opcionais.
  • Flexibilidade: O processo de construção pode ser personalizado ou dividido em várias etapas.
  • Imutabilidade: Pode ser usado para construir objetos imutáveis, pois o objeto final é completamente configurado antes de ser criado.
  • Evitam construtores longos: Em vez de usar um construtor com muitos parâmetros, o Builder permite definir parâmetros de maneira flexível.

Desvantagens do Builder

  • Mais código: Implementar o padrão Builder pode resultar em mais classes e código, o que pode parecer um overhead em casos simples.
  • Necessidade de configuração: Para objetos relativamente simples, a configuração adicional do Builder pode não ser justificada.

Quando não usar o Builder

  • Quando a criação de objetos é simples e envolve poucos parâmetros.
  • Quando não há necessidade de criar diferentes variações do objeto.

Aplicações comuns

O padrão Builder é amplamente utilizado para a criação de objetos que possuem muitos parâmetros opcionais, como:

  • Objetos de configuração em APIs e frameworks.
  • Criação de objetos complexos como carros, casas, ou documentos.
  • Em bibliotecas como o próprio Java, o padrão Builder é utilizado em classes como StringBuilder (embora tecnicamente não seja o padrão formal de design "Builder", ele oferece uma interface fluente similar).

Resumo

O padrão Builder é um padrão criacional que facilita a construção de objetos complexos, separando o processo de construção em etapas configuráveis. Ele permite criar diferentes representações de um objeto, tornando o código mais legível e flexível, especialmente quando há muitos atributos opcionais ou parâmetros.