Menu
Coddy logo textTech

Padrão Factory

Parte da seção Programação Orientada a Objetos do Journey de GO da Coddy — lição 87 de 107.

O padrão Factory delega a criação de objetos para uma função ou método separado, permitindo que você crie instâncias sem expor a lógica de criação. Ao contrário do Singleton, que controla a contagem de instâncias, o Factory foca na criação flexível de objetos com base em parâmetros de entrada.

Em Go, uma factory é tipicamente uma função que retorna um tipo interface, permitindo que você crie diferentes tipos concretos através de uma API unificada:

type Notifier interface {
    Send(message string) string
}

type EmailNotifier struct{}
type SMSNotifier struct{}

func (e EmailNotifier) Send(message string) string {
    return "Email: " + message
}

func (s SMSNotifier) Send(message string) string {
    return "SMS: " + message
}

func NewNotifier(notifierType string) Notifier {
    switch notifierType {
    case "email":
        return EmailNotifier{}
    case "sms":
        return SMSNotifier{}
    default:
        return EmailNotifier{}
    }
}

A função factory NewNotifier encapsula a decisão de qual tipo concreto criar. O código cliente trabalha apenas com a interface Notifier, permanecendo alheio à implementação específica:

notifier := NewNotifier("sms")
result := notifier.Send("Hello!")  // "SMS: Hello!"

Este padrão se destaca quando você precisa criar objetos com base em condições de tempo de execução, deseja centralizar uma lógica de inicialização complexa ou precisa adicionar novos tipos facilmente sem modificar o código do cliente. Basta adicionar uma nova struct implementando a interface e atualizar a função factory.

challenge icon

Desafio

Fácil

Vamos construir um sistema conversor de documentos usando o padrão Factory! Você criará uma fábrica que produz diferentes conversores de documentos com base no formato de destino, permitindo que o código do cliente trabalhe com qualquer conversor por meio de uma interface unificada.

Você organizará seu código em dois arquivos:

  • converter.go: Defina sua interface de conversor e as implementações concretas.

    Crie uma interface Converter com um método Convert(content string) string que recebe o conteúdo do documento e retorna a saída convertida.

    Implemente três tipos de conversores:

    • PDFConverter — seu método Convert retorna "PDF: " + content
    • HTMLConverter — seu método Convert retorna "HTML: <p>" + content + "</p>"
    • MarkdownConverter — seu método Convert retorna "MD: # " + content

    Crie uma função de fábrica NewConverter(format string) Converter que retorna o conversor apropriado com base na string de formato ("pdf", "html" ou "markdown"). Para qualquer formato não reconhecido, retorne um PDFConverter como padrão.

  • main.go: Use sua fábrica para criar conversores e processar documentos.

    Leia um tipo de formato e o conteúdo do documento. Use a fábrica para criar o conversor apropriado, depois converta o conteúdo e imprima o resultado.

As seguintes entradas serão fornecidas:

  • Linha 1: Tipo de formato ("pdf", "html", "markdown" ou outro valor)
  • Linha 2: Conteúdo do documento a ser convertido

Por exemplo, dado:

html
Welcome to Go Programming

Sua saída deve ser:

HTML: <p>Welcome to Go Programming</p>

E dado:

markdown
Chapter One

Sua saída deve ser:

MD: # Chapter One

E dado:

pdf
Annual Report 2024

Sua saída deve ser:

PDF: Annual Report 2024

E dado:

docx
Meeting Notes

Sua saída deve ser:

PDF: Meeting Notes

Observe como o código principal não precisa saber sobre tipos específicos de conversores — ele apenas solicita um conversor à fábrica e usa a interface. Isso facilita a adição de novos formatos posteriormente sem alterar o código do cliente!

Folha de consulta

O padrão Factory delega a criação de objetos para uma função separada, permitindo que você crie instâncias sem expor a lógica de criação. Ele foca na criação flexível de objetos com base em parâmetros de entrada.

Uma função factory retorna um tipo de interface, permitindo a criação de diferentes tipos concretos por meio de uma API unificada:

type Notifier interface {
    Send(message string) string
}

type EmailNotifier struct{}
type SMSNotifier struct{}

func (e EmailNotifier) Send(message string) string {
    return "Email: " + message
}

func (s SMSNotifier) Send(message string) string {
    return "SMS: " + message
}

func NewNotifier(notifierType string) Notifier {
    switch notifierType {
    case "email":
        return EmailNotifier{}
    case "sms":
        return SMSNotifier{}
    default:
        return EmailNotifier{}
    }
}

O código do cliente trabalha apenas com a interface, permanecendo alheio às implementações específicas:

notifier := NewNotifier("sms")
result := notifier.Send("Hello!")  // "SMS: Hello!"

Este padrão é útil quando você precisa criar objetos com base em condições de tempo de execução, deseja centralizar a lógica de inicialização complexa ou precisa adicionar novos tipos sem modificar o código do cliente.

Experimente você mesmo

package main

import (
	"bufio"
	"fmt"
	"os"
)

func main() {
	scanner := bufio.NewScanner(os.Stdin)
	
	// Ler o tipo de formato
	scanner.Scan()
	format := scanner.Text()
	
	// Ler o conteúdo do documento
	scanner.Scan()
	content := scanner.Text()
	
	// TODO: Usar a factory para criar o conversor apropriado
	// TODO: Converter o conteúdo e imprimir o resultado
	
	fmt.Println(result)
}
quiz iconTeste seus conhecimentos

Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.

Todas as lições de Programação Orientada a Objetos