Padrão Abstract Factory
Parte da seção Programação Orientada a Objetos do Journey de GO da Coddy. Lição 88 de 107.
O padrão Abstract Factory estende o padrão Factory ao criar famílias de objetos relacionados sem especificar seus tipos concretos. Em vez de uma única função de fábrica, você define uma interface de fábrica que várias fábricas concretas implementam, cada uma produzindo um conjunto consistente de objetos relacionados.
Considere um toolkit de UI que precisa criar buttons e checkboxes. Diferentes sistemas operacionais exigem implementações diferentes, mas os componentes devem funcionar juntos de forma consistente:
type Button interface {
Render() string
}
type Checkbox interface {
Check() string
}
// Interface de fábrica abstrata
type GUIFactory interface {
CreateButton() Button
CreateCheckbox() Checkbox
}Cada fábrica concreta produz uma família de componentes relacionados:
// Família Windows
type WindowsButton struct{}
func (w WindowsButton) Render() string { return "Windows Button" }
type WindowsCheckbox struct{}
func (w WindowsCheckbox) Check() string { return "Windows Checkbox" }
type WindowsFactory struct{}
func (w WindowsFactory) CreateButton() Button { return WindowsButton{} }
func (w WindowsFactory) CreateCheckbox() Checkbox { return WindowsCheckbox{} }
// Família Mac
type MacButton struct{}
func (m MacButton) Render() string { return "Mac Button" }
type MacCheckbox struct{}
func (m MacCheckbox) Check() string { return "Mac Checkbox" }
type MacFactory struct{}
func (m MacFactory) CreateButton() Button { return MacButton{} }
func (m MacFactory) CreateCheckbox() Checkbox { return MacCheckbox{} }O código do cliente trabalha com a interface de fábrica, permanecendo independente das implementações concretas:
func BuildUI(factory GUIFactory) {
button := factory.CreateButton()
checkbox := factory.CreateCheckbox()
fmt.Println(button.Render(), checkbox.Check())
}Use a Fábrica Abstrata quando seu sistema precisar trabalhar com várias famílias de produtos relacionados e você quiser garantir que componentes da mesma família sejam usados em conjunto. Ela é mais complexa do que uma Fábrica simples, portanto recorra a ela somente quando realmente precisar gerenciar famílias de produtos.
Desafio
FácilVamos criar um sistema de loja de móveis usando o padrão Abstract Factory! Você criará fábricas que produzem famílias de itens de mobiliário relacionados: cada fábrica produz um estilo consistente (Modern ou Vintage), garantindo que as cadeiras e mesas da mesma fábrica combinem esteticamente.
Você organizará seu código em três arquivos:
furniture.go: defina suas interfaces de produto e os tipos concretos de móveis.Crie duas interfaces de produto:
Chaircom um métodoSitOn() stringTablecom um métodoPlaceItems() string
Implemente duas famílias de móveis:
- Família Modern:
ModernChairretornaSitting on a sleek modern chaireModernTableretornaPlacing items on a glass modern table - Família Vintage:
VintageChairretornaSitting on an ornate vintage chaireVintageTableretornaPlacing items on a wooden vintage table
factory.go: defina sua interface de fábrica abstrata e as fábricas concretas.Crie uma interface
FurnitureFactorycom dois métodos:CreateChair() ChairCreateTable() Table
Implemente duas fábricas concretas:
ModernFactory, que produzModernChaireModernTableVintageFactory, que produzVintageChaireVintageTable
Crie também uma função
GetFactory(style string) FurnitureFactoryque retorna a fábrica apropriada com base no estilo (modernouvintage). UseModernFactorycomo padrão para estilos não reconhecidos.main.go: use suas fábricas para mobiliar cômodos.Crie uma função
FurnishRoom(factory FurnitureFactory) stringque usa a fábrica para criar uma cadeira e uma mesa e, em seguida, retorna uma string formatada mostrando ambas as ações em linhas separadas.Leia uma entrada de estilo, obtenha a fábrica apropriada, mobílie um cômodo e imprima o resultado.
As seguintes entradas serão fornecidas:
- Linha 1: estilo do móvel (
modern,vintageou algo diferente)
Por exemplo, dada a entrada:
modernSua saída deve ser:
Sitting on a sleek modern chair
Placing items on a glass modern tableE dada a entrada:
vintageSua saída deve ser:
Sitting on an ornate vintage chair
Placing items on a wooden vintage tableE dada a entrada:
rusticSua saída deve ser:
Sitting on a sleek modern chair
Placing items on a glass modern tableObserve como a função FurnishRoom funciona com qualquer fábrica por meio da interface. Ela não sabe se está criando móveis modernos ou vintage. Isso garante que todos os móveis de um cômodo venham da mesma família, mantendo um estilo consistente!
Experimente você mesmo
package main
import "fmt"
// FurnishRoom usa uma factory para criar móveis e retorna o resultado
// TODO: Implemente esta função
// - Use a factory para criar uma cadeira e uma mesa
// - Retorne uma string com o resultado de SitOn() na primeira linha e o resultado de PlaceItems() na segunda linha
func FurnishRoom(factory FurnitureFactory) string {
// TODO: Crie a cadeira e a mesa usando a factory
// TODO: Retorne a string formatada com ambas as ações em linhas separadas
return ""
}
func main() {
var style string
fmt.Scanln(&style)
// TODO: Obtenha a factory apropriada com base no style
// TODO: Mobilie uma sala usando a factory
// TODO: Imprima o resultado
}
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 ExternosWorkspace e Módulos do GoPacotes e ImportsNomes Exportados vs. Não ExportadosIntrodução à OOP em GoStructs como ClassesDefinindo Métodos em StructsReceptores de Ponteiro vs. de ValorInicialização de StructsFunções ConstrutorasRecapitulação — Calculadora Simples4Interfaces
Introdução às InterfacesImplementação ImplícitaInterface como ContratoInterface Vazia (any)Asserção de TipoSwitch de TipoComposição de InterfacesInterfaces Stringer e ErrorRecapitulação - Calculadora de Formas7Encapsulamento
Campos Exportados vs. Não ExportadosEncapsulamento no Nível de PacoteMétodos Getters e SettersOcultação de Informações em GoRecapitulação - Registros de Alunos10Genéricos (Go 1.18+)
Introdução aos genéricosParâmetros de tipoRestrições de tipoStructs genéricasAlternativa 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 Strategy2Tipos e Structs em Profundidade
Tipos Básicos e CompostosDefinições de Tipos PersonalizadosTags de StructStructs AnônimasStructs AninhadasValores Zero e PadrõesRecapitulação - Livro de Contatos5Composição em vez de herança
Por que Go não tem herançaNoções básicas de incorporação de structsPromoção de métodosIncorporação de várias structsIncorporação vs agregaçãoOcultação de métodos incorporadosRecapitulação - Hierarquia de funcionários8Tratamento de Erros e OOP
A interface errorTipos de Erro PersonalizadosEncapsulamento de Erros (fmt.Errorf)Erros Sentinelaerrors.Is() e errors.As()Panic, Defer e RecoverRecapitulação - Analisador de Arquivos3Ponteiros e Memória
Fundamentos de Ponteiros em GoPonteiros para StructsPassagem por Valor vs. ReferênciaA Função new()Coleta de Lixo em GoRecapitulação - Construtor de Lista Ligada6Polimorfismo em Go
Polimorfismo via InterfacesDuck Typing em GoRegras de Satisfação de InterfacesColeções PolimórficasInjeção de DependênciasRecapitulação - Processador de Pagamentos9Concorrência e OOP
Fundamentos de GoroutinesCanais e comunicaçãoCanais com e sem bufferInstrução selectsync.Mutex e sync.RWMutexsync.WaitGroupDesign de structs thread-safeRevisão - Worker PoolPratique por conta própria: Compilador de Go online