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.
Desafio
FácilVamos 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
Convertercom um métodoConvert(content string) stringque recebe o conteúdo do documento e retorna a saída convertida.Implemente três tipos de conversores:
PDFConverter— seu métodoConvertretorna"PDF: " + contentHTMLConverter— seu métodoConvertretorna"HTML: <p>" + content + "</p>"MarkdownConverter— seu métodoConvertretorna"MD: # " + content
Crie uma função de fábrica
NewConverter(format string) Converterque retorna o conversor apropriado com base na string de formato ("pdf","html"ou"markdown"). Para qualquer formato não reconhecido, retorne umPDFConvertercomo 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 ProgrammingSua saída deve ser:
HTML: <p>Welcome to Go Programming</p>E dado:
markdown
Chapter OneSua saída deve ser:
MD: # Chapter OneE dado:
pdf
Annual Report 2024Sua saída deve ser:
PDF: Annual Report 2024E dado:
docx
Meeting NotesSua saída deve ser:
PDF: Meeting NotesObserve 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)
}
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
1Fundamentos de OOP em Go
Arquivos ExternosGo Workspace e MódulosPacotes e ImportaçõesNomes Exportados vs Não ExportadosIntrodução a OOP em GoStructs como ClassesDefinindo Métodos em StructsRecebedores de Ponteiro vs ValorInicialização de StructsFunções ConstrutorasRecapitulação - Calculadora Simples4Interfaces
Introdução a InterfacesImplementação ImplícitaInterface como ContratoInterface Vazia (any)Type AssertionType SwitchComposição de InterfacesInterfaces Stringer & ErrorRecapitulação - Calculadora de Formas7Encapsulamento
Campos Exportados vs Não ExportadosEncapsulamento em Nível de PacoteMétodos Getter e SetterOcultação de Informação em GoRecapitulação - Registros de Estudantes10Generics (Go 1.18+)
Introdução a GenericsParâmetros de TipoRestrições de TipoStructs GenéricasSolução Alternativa para Métodos GenéricosRecapitulação - Coleção Genérica13Padrões de Projeto Parte 1
Introdução aos Padrões de ProjetoPadrão SingletonPadrão FactoryPadrão Abstract FactoryPadrão ObserverPadrão Strategy2Mergulho Profundo em Tipos e Structs
Tipos Básicos e CompostosDefinições de Tipos PersonalizadosStruct TagsStructs AnônimasStructs AninhadasZero Values e PadrõesRecapitulação - Agenda de Contatos5Composição em vez de Herança
Por que Go não possui HerançaFundamentos de Incorporação de StructsPromoção de MétodosIncorporando Múltiplas StructsIncorporação vs AgregaçãoShadowing de Métodos IncorporadosRecapitulação - Hierarquia de Funcionários8Tratamento de Erros e OOP
A Interface errorTipos de Erro PersonalizadosError Wrapping (fmt.Errorf)Erros Sentinelaerrors.Is() e errors.As()Panic, Defer e RecoverRecapitulação - File Parser3Ponteiros e Memória
Fundamentos de Ponteiros em GoPonteiros para StructsPassagem por Valor vs ReferênciaA Função new()Garbage Collection em GoRecapitulação - Construtor de Lista Encadeada6Polimorfismo em Go
Polimorfismo via InterfacesDuck Typing em GoRegras de Satisfação de InterfaceColeções PolimórficasInjeção de DependênciaRecapitulação - Processador de Pagamentos9Concorrência e OOP
Fundamentos de GoroutinesCanais e ComunicaçãoCanais com Buffer vs. Sem BufferInstrução Selectsync.Mutex e sync.RWMutexsync.WaitGroupDesign de Structs Thread-SafeRecapitulação - Worker Pool