Menu
Coddy logo textTech

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 múltiplas fábricas concretas implementam, cada uma produzindo um conjunto consistente de objetos relacionados.

Considere um toolkit de UI que precisa criar botões 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 da factory 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 cliente trabalha com a interface da fábrica, permanecendo independente de implementações concretas:

func BuildUI(factory GUIFactory) {
    button := factory.CreateButton()
    checkbox := factory.CreateCheckbox()
    fmt.Println(button.Render(), checkbox.Check())
}

Use o Abstract Factory quando seu sistema precisar trabalhar com múltiplas famílias de produtos relacionados e você quiser garantir que os componentes da mesma família sejam usados juntos. Ele é mais complexo do que um Factory simples, portanto, utilize-o apenas quando você realmente precisar gerenciar famílias de produtos.

challenge icon

Desafio

Fácil

Vamos construir 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 (Moderno ou Vintage), garantindo que cadeiras e mesas da mesma fábrica combinem esteticamente.

Você organizará seu código em três arquivos:

  • furniture.go: Defina suas interfaces de produtos e tipos de móveis concretos.

    Crie duas interfaces de produto:

    • Chair com um método SitOn() string
    • Table com um método PlaceItems() string

    Implemente duas famílias de móveis:

    • Família Modern: ModernChair retorna "Sitting on a sleek modern chair" e ModernTable retorna "Placing items on a glass modern table"
    • Família Vintage: VintageChair retorna "Sitting on an ornate vintage chair" e VintageTable retorna "Placing items on a wooden vintage table"
  • factory.go: Defina sua interface de fábrica abstrata e fábricas concretas.

    Crie uma interface FurnitureFactory com dois métodos:

    • CreateChair() Chair
    • CreateTable() Table

    Implemente duas fábricas concretas:

    • ModernFactory que produz ModernChair e ModernTable
    • VintageFactory que produz VintageChair e VintageTable

    Também crie uma função GetFactory(style string) FurnitureFactory que retorna a fábrica apropriada com base no estilo ("modern" ou "vintage"). Use ModernFactory como padrão para estilos não reconhecidos.

  • main.go: Use suas fábricas para mobiliar cômodos.

    Crie uma função FurnishRoom(factory FurnitureFactory) string que usa a fábrica para criar uma cadeira e uma mesa, e então retorna uma string formatada mostrando ambas as ações em linhas separadas.

    Leia uma entrada de estilo, obtenha a fábrica apropriada, mobilie um cômodo e imprima o resultado.

As seguintes entradas serão fornecidas:

  • Linha 1: Estilo de móveis ("modern", "vintage", ou algo diferente)

Por exemplo, dado:

modern

Sua saída deve ser:

Sitting on a sleek modern chair
Placing items on a glass modern table

E dado:

vintage

Sua saída deve ser:

Sitting on an ornate vintage chair
Placing items on a wooden vintage table

E dado:

rustic

Sua saída deve ser:

Sitting on a sleek modern chair
Placing items on a glass modern table

Observe como a função FurnishRoom funciona com qualquer fábrica através da interface — ela não sabe se está criando móveis modernos ou vintage. Isso garante que todos os móveis em um cômodo venham da mesma família, mantendo um estilo consistente!

Folha de consulta

O padrão Abstract Factory cria famílias de objetos relacionados sem especificar seus tipos concretos. Ele define uma interface de fábrica que múltiplas fábricas concretas implementam, cada uma produzindo um conjunto consistente de objetos relacionados.

Estrutura

Defina interfaces de produto para cada tipo de objeto:

type Button interface {
    Render() string
}

type Checkbox interface {
    Check() string
}

Crie uma interface de fábrica abstrata que declara métodos para criar cada tipo de produto:

type GUIFactory interface {
    CreateButton() Button
    CreateCheckbox() Checkbox
}

Implementações Concretas

Implemente famílias de produtos concretos onde cada família possui estilo ou comportamento consistente:

// Windows family
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{} }

// Mac family
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{} }

Código do Cliente

O código do cliente trabalha com a interface da fábrica, permanecendo independente de implementações concretas:

func BuildUI(factory GUIFactory) {
    button := factory.CreateButton()
    checkbox := factory.CreateCheckbox()
    fmt.Println(button.Render(), checkbox.Check())
}

Quando Usar

Use o Abstract Factory quando seu sistema precisar trabalhar com múltiplas famílias de produtos relacionados e você quiser garantir que os componentes da mesma família sejam usados juntos. Ele é mais complexo do que um Factory simples, portanto, use-o apenas quando você realmente precisar gerenciar famílias de produtos.

Experimente você mesmo

package main

import "fmt"

// FurnishRoom usa uma factory para criar móveis e retorna o resultado
// TODO: Implementar 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: Criar cadeira e mesa usando a factory
	// TODO: Retornar uma string formatada com ambas as ações em linhas separadas
	return ""
}

func main() {
	var style string
	fmt.Scanln(&style)

	// TODO: Obter a factory apropriada com base no style
	// TODO: Mobiliar um quarto usando a factory
	// TODO: Imprimir o resultado
}
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