Skip to content

Commit

Permalink
Merge pull request #55 from hopesoh/builder_pattern
Browse files Browse the repository at this point in the history
Builder pattern
  • Loading branch information
gleiceellen authored Oct 12, 2023
2 parents 016faf7 + f5dc387 commit f1713f0
Show file tree
Hide file tree
Showing 7 changed files with 217 additions and 0 deletions.
140 changes: 140 additions & 0 deletions Design Patterns/Builder/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
# Builder Pattern
O padrão **Builder**, que é um dos _23 padrões de design do
Gang of Four (GoF)_, é um padrão de criação
que permite construir objetos complexos passo a passo.
Além de encapsular a construção, é capaz de produzir diferentes
tipos e representações de um item utilizando o mesmo código.

## Motivação
O padrão Builder foi introduzido para resolver alguns
dos problemas de outros padrões de design semelhantes, como
o **Factory** e **Abstract Factory**.

Imagine uma classe que possua muitos atributos, sendo eles,
variados entre opcionais e obrigatórios. No momento de criação
de uma instância, os valores para os atributos obrigatórios sempre
precisarão existir. Entretanto, a variação desses objetos com os campos
opcionais pode ser enorme.

Para solucionar e adequar os construtores aos casos conforme
a necessidade, tradicionalmente, é usado o conceito de
**construtor telescópico**: onde o primeiro construtor
ocupa apenas os campos obrigatórios, para cada campo opcional,
existe um construtor adicional que utiliza os campos obrigatórios
**mais** os campos opcionais.

``` java
class Pizza {
public Pizza (Size size, Dough dought) { ... }
public Pizza (Size size, Dough dought, Sauce sauce) { ... }
public Pizza (Size size, Dough dought, Sauce sauce, List<Toppings> toppings) { ... }
// ...
}
```

O maior problema dessa solução, se dá pela manutenção desse
código e leitura a longo prazo, pois os construtores tendem
a aumentar conforme aumenta o número de atributos da classe.

Outra possibilidade, é a utilização do **padrão JavaBeans**, ou
seja, a criação de um construtor sem parâmetros e setters
para inicialização dos valores necessários.

```java
...
Pizza pizza = new Pizza();
pizza.setSize(SMALL);
pizza.setSauce(RED);
...
```

Uma desvantagem relacionada é que o padrão JavaBeans
exclui a possibilidade de tornar uma classe imutável e
requer esforço adicional por parte do programador para
garantir a segurança da thread. Se eu esqueço um dos parâmetros
obrigatórios, como o tamanho, por exemplo, posso ter problemas
futuros na utilização desse objeto.

Com o objetivo de resolver esses problemas, surgiu o padrão
Builder.

Algumas vantagens e desvantagens dessa abordagem são:


| Vantagens | Desvantagens |
|------------------------------------------------------------|-----------------------------------------------------------------------|
| Encapsulamento bem definido | Sempre é necessário criar um builder para a instanciação de um objeto |
| Flexibilidade e possibilidade de customização de um objeto | Mais verboso que os demais métodos |
| Imutabilidade | |
| Segurança e integridade dos dados | |
| Reusabilidade de código | |
| Maior controle no processo de construção de um objeto | |

## Exemplo

No nosso caso de uso, temos a construção de uma `Pizza`. Temos
algumas possíveis variações aqui: Com ou sem azeitonas,
tipos diferentes de tamanho, tipos de massa, possibilidades
de molhos, quantidades e tipos de toppings
(ou sem, se você tiver gostos peculiares).

A estrutura do projeto é a seguinte:
```
.
├── ...
├── com.builder.java # Pacote destinado ao exemplo
│ ├── Dought # Enum de tipos de Massa
│ ├── Pizza # Classe da construção da Pizza
│ ├── Sauce # Enum de tipos de Molho
│ ├── Size # Enum de tipos de Tamanho
│ └── Topping # Enum de tipos de Toppings
├── README.md # Documentação do exemplo
└── ...
```


Uma forma de utilizar o padrão para a construção
dessas Pizzas é como no exemplo abaixo:

``` java
Pizza sausagePizza = new PizzaBuilder(Size.SMALL, Dought.WHITE_WHOLE_WHEAT)
.withSauce(Sauce.RED)
.withTopping(Topping.CHEESE, Topping.SAUSAGE, Topping.ONION)
.withOlive()
.build();

Pizza cheesePizza = new PizzaBuilder(Size.LARGE, Dought.WHITE_WHOLE_WHEAT)
.withSauce(Sauce.WHITE)
.withTopping(Topping.CHEESE)
.build();
```

## Casos de Uso
- [java.lang.StringBuilder](https://docs.oracle.com/javase/8/docs/api/java/lang/StringBuilder.html)
- [java.lang.StringBuffer](https://docs.oracle.com/javase/8/docs/api/java/lang/StringBuffer.html#append-boolean-)

## Para saber mais
Os exemplos mostrados aqui, foram inspirados na versão do
padrão Builder de Joshua Bloch, autor do livro Effective Java.
Essa versão alternativa, é uma variação da versão original
apresentado pelo Gang of Four, que contém outros
elementos, entre eles, um Director, responsável
por notificar o construtor sempre que uma parte do produto
deve ser construída.

Caso tenha curiosidade, o livro **Design Patterns: Elements of Reusable Object-Oriented Software**,
o site do Refactor Guru e livro Head First Design Patterns,
todos presentes na seção **Fonte**, abordam o padrão
em sua forma original.


## Fonte
- [Design Patterns: Elements of Reusable Object-Oriented Software](https://www.amazon.com/Design-Patterns-Object-Oriented-Addison-Wesley-Professional-ebook/dp/B000SEIBB8)
- [Refactoring Guru](https://refactoring.guru/design-patterns/builder)
- [Head First Design Patterns](https://www.amazon.com.br/Cabe%C3%A7a-Padr%C3%B5es-Projetos-Eric-Freeman/dp/8576081741)
- [Effective Java](https://www.amazon.com.br/Effective-Java-English-Joshua-Bloch-ebook/dp/B078H61SCH/ref=sr_1_1?__mk_pt_BR=%C3%85M%C3%85%C5%BD%C3%95%C3%91&crid=2VO8TOTTXMH5Y&keywords=effective+java&qid=1696547006&s=books&sprefix=effective+java%2Cstripbooks%2C148&sr=1-1)
- [DigitalOcean](https://www.digitalocean.com/community/tutorials/builder-design-pattern-in-java)
- [JournalDev: Builder Design Pattern](https://www.youtube.com/watch?v=D5NK5qMM14g&ab_channel=JournalDevITServices)
- [Exploring Joshua Bloch’s Builder design pattern in Java](https://blogs.oracle.com/javamagazine/post/exploring-joshua-blochs-builder-design-pattern-in-java)

3 changes: 3 additions & 0 deletions Design Patterns/Builder/com.builder.java/Dought.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
enum Dought {
WHOLE_WHEAT, WHITE_WHOLE_WHEAT;
}
53 changes: 53 additions & 0 deletions Design Patterns/Builder/com.builder.java/Pizza.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import java.util.*;

import static java.util.Arrays.stream;

public class Pizza {

private final Size size;
private final Dought dought;
private final Sauce sauce;
private final Set<Topping> toppings;
private boolean olive;

public static class PizzaBuilder {
private final Size size;
private final Dought dought;
private Sauce sauce;
private EnumSet<Topping> toppings = EnumSet.noneOf(Topping.class);
private boolean olive;

public PizzaBuilder(Size size, Dought dought) {
this.size = size;
this.dought = dought;
}

public PizzaBuilder withTopping(Topping... topping) {
toppings.addAll(stream(topping).toList());
return this;
}

public PizzaBuilder withSauce(Sauce sauce) {
this.sauce = sauce;
return this;
}

public PizzaBuilder withOlive() {
this.olive = true;
return this;
}

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


}
private Pizza(PizzaBuilder builder) {
this.size = builder.size;
this.dought = builder.dought;
this.sauce = builder.sauce;
this.toppings = builder.toppings;
this.olive = builder.olive;
}
}
3 changes: 3 additions & 0 deletions Design Patterns/Builder/com.builder.java/Sauce.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
enum Sauce {
WHITE, RED;
}
3 changes: 3 additions & 0 deletions Design Patterns/Builder/com.builder.java/Size.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
public enum Size {
SMALL, MEDIUM, LARGE;
}
3 changes: 3 additions & 0 deletions Design Patterns/Builder/com.builder.java/Topping.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
enum Topping {
HAM, MUSHROOM, CORN, ONION, SAUSAGE, CHEESE;
}
12 changes: 12 additions & 0 deletions java-trainning.iml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/Design Patterns/Strategy Pattern/com.strategy.java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/Design Patterns/Builder/com.builder.java" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

0 comments on commit f1713f0

Please sign in to comment.