Factory Design Pattern
Tags: go, designpatterns, coding, softwaredevelopment
Published: 2024-07-04 15:23:44

O padrão de design Factory é amplamente utilizado na programação orientada a objetos. Ele oferece uma interface para criar objetos, mas permite que as subclasses decidam quais classes instanciar. Neste artigo, vamos explorar como implementar o padrão Factory em Golang, entender seus benefícios e analisar um exemplo prático de uso inspirado em situações do dia-a-dia.

## O que é o Factory?
O Factory define uma interface para criar objetos, mas delega a responsabilidade de instanciar a classe concreta às subclasses. Isso promove a criação de objetos de maneira desacoplada e flexível, permitindo que o código seja mais modular e fácil de manter.

## Benefícios
* Desacoplamento: Separa a criação de objetos da sua implementação, promovendo um código mais limpo e modular.
* Flexibilidade: Facilita a introdução de novas classes sem modificar o código existente.
* Manutenção: Torna o código mais fácil de manter e evoluir, pois a lógica de criação está centralizada em um único lugar.

## Implementando uma Factory
Vamos utilizar um exemplo do dia-a-dia para ilustrar o padrão Factory: um sistema para pedidos de comida, onde alguns diferentes tipos de refeições (Pizza e Salada) podem ser criados.

### 1 - Criando a interface
Primeiro, precisamos definir uma interface que será implementada por todas as "classes concretas" de refeições.

```go
package main

type Food interface {
	Prepare()
}
```

### 2 - Criando um ENUM e implementando a interface 
Para facilitar a nossa vida durante o desenvolvimento e evitar de digitar algo errado durante a validação, uma boa prática é criar um ENUM para ter uma consistência e também facilitar caso queiramos adicionar novas comidas no futuro

```go
package main

type FoodType int

const (
	PizzaType FoodType = iota
	SaladType
)

type Food interface {
	Prepare()
}
```

E agora vamos implementar a interface `Food`. No exemplo vamos apenas exibir uma mensagem, na vida real aqui é onde seria criado o objeto que estamos trabalhando

```go
package main

type FoodType int

const (
	PizzaType FoodType = iota
	SaladType
)

type Food interface {
	Prepare()
}

type Pizza struct{}

func (p Pizza) Prepare() {
	fmt.Println("Preparing a Pizza...")
}

type Salad struct{}

func (s Salad) Prepare() {
	fmt.Println("Preparing a Salad...")
}
```

### 3 - Criando a Factory

Agora, vamos criar a factory que decidirá qual classe concreta instanciar com base no enum que recebeu como parâmetro.

```go
package main

type FoodFactory struct{}

func (f FoodFactory) CreateFood(ft FoodType) Food {
	switch ft {
	case PizzaType:
		return &Pizza{}
	case SaladType:
		return &Salad{}
	default:
		return nil
	}
}
```

### 4 - Utilizando a Factory
Finalmente, vamos utilizar a fábrica para criar nossas comidas.

```go 
package main

func main() {
	kitchen := FoodFactory{}

	pizza := kitchen.CreateFood(PizzaType)
	if pizza != nil {
		pizza.Prepare()
	}

	salad := kitchen.CreateFood(SaladType)
	if salad != nil {
		salad.Prepare()
	}
}
```

Esse será o resultado após rodarmos nossa aplicação:
```shell
Preparing a Pizza...
Preparing a Salad...
```

### Resumo do que fizemos

1. Interface `Food`: Define o contrato que todas as refeições concretas devem seguir, garantindo que todas implementem o método Prepare.
2. Enum `FoodType`: Utiliza constantes tipadas para representar os diferentes tipos de comida, aumentando a legibilidade e a segurança do código.
3. Classes concretas (`Pizza` e `Salad`): Implementam a interface Food e fornecem suas próprias implementações do método Prepare.
4. `FoodFactory`: Contém a lógica de criação de objetos. O método CreateFood decide qual classe concreta instanciar com base no enum FoodType.
5. Método `main`: Demonstra o uso da fábrica para criar diferentes objetos e chamar seus métodos, ilustrando a flexibilidade e o desacoplamento proporcionados pelo padrão Factory.

## Conclusão

O padrão de design Factory é uma poderosa ferramenta para promover o desacoplamento e a flexibilidade na criação de objetos. Em Golang, a implementação deste padrão é direta e eficaz, permitindo a criação de sistemas modulares e fáceis de manter. Com o uso de interfaces e fábricas, podemos centralizar a lógica de criação e simplificar a evolução do código à medida que novos requisitos surgem.