DEV Community

Rafael Pazini
Rafael Pazini

Posted on

Factory Design Pattern

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.

package main

type Food interface {
    Prepare()
}
Enter fullscreen mode Exit fullscreen mode

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

package main

type FoodType int

const (
    PizzaType FoodType = iota
    SaladType
)

type Food interface {
    Prepare()
}
Enter fullscreen mode Exit fullscreen mode

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

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...")
}
Enter fullscreen mode Exit fullscreen mode

3 - Criando a Factory

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

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
    }
}
Enter fullscreen mode Exit fullscreen mode

4 - Utilizando a Factory

Finalmente, vamos utilizar a fábrica para criar nossas comidas.

package main

func main() {
    kitchen := FoodFactory{}

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

    salad := kitchen.CreateFood(SaladType)
    if salad != nil {
        salad.Prepare()
    }
}
Enter fullscreen mode Exit fullscreen mode

Esse será o resultado após rodarmos nossa aplicação:

Preparing a Pizza...
Preparing a Salad...
Enter fullscreen mode Exit fullscreen mode

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.

Top comments (0)