Sobes.tech
Middle

Fale sobre o padrão Factory.

sobes.tech IA

Resposta da IA

Uma fábrica é um padrão de design creacional que fornece uma interface comum para criar objetos na superclasse, enquanto que as subclasses podem modificar o tipo de objetos criados.

  • Fábrica simples (Simple Factory): Não é um padrão na sua forma pura, mas sim uma idiomática. Uma classe com um método que cria objetos com base nos parâmetros de entrada.

    package main
    
    import "fmt"
    
    type Product interface {
    	Use()
    }
    
    type ConcreteProductA struct{}
    
    func (p *ConcreteProductA) Use() {
    	fmt.Println("A usar Produto Concreto A")
    }
    
    type ConcreteProductB struct{}
    
    func (p *ConcreteProductB) Use() {
    	fmt.Println("A usar Produto Concreto B")
    }
    
    type SimpleFactory struct{}
    
    func (f *SimpleFactory) CreateProduct(t string) Product {
    	switch t {
    	case "A":
    		return &ConcreteProductA{}
    	case "B":
    		return &ConcreteProductB{}
    	default:
    		return nil
    	}
    }
    
    func main() {
    	factory := SimpleFactory{}
    	productA := factory.CreateProduct("A")
    	productA.Use()
    
    	productB := factory.CreateProduct("B")
    	productB.Use()
    }
    
  • Método de fábrica (Factory Method): Define uma interface para criar um objeto, mas permite que as subclasses decidam qual classe instanciar.

    package main
    
    import "fmt"
    
    // Interface do produto
    type Product interface {
    	Operation() string
    }
    
    // Produto concreto A
    type ConcreteProduct1 struct{}
    
    func (p *ConcreteProduct1) Operation() string {
    	return "Resultado do ConcreteProduct1"
    }
    
    // Produto concreto B
    type ConcreteProduct2 struct{}
    
    func (p *ConcreteProduct2) Operation() string {
    	return "Resultado do ConcreteProduct2"
    }
    
    // Interface do criador
    type Creator interface {
    	FactoryMethod() Product
    	SomeOperation() string
    }
    
    // Estrutura base do criador
    type BaseCreator struct{}
    
    func (bc *BaseCreator) SomeOperation() string {
    	// Chamada do método de fábrica para obter um objeto de produto
    	product := bc.FactoryMethod()
    	// Uso do produto
    	result := "O código do criador acabou de trabalhar com " + product.Operation()
    	return result
    }
    
    // Criador concreto A
    type ConcreteCreator1 struct {
    	BaseCreator
    }
    
    func (cc *ConcreteCreator1) FactoryMethod() Product {
    	return &ConcreteProduct1{} // Cria Produto concreto A
    }
    
    // Criador concreto B
    type ConcreteCreator2 struct {
    	BaseCreator
    }
    
    func (cc *ConcreteCreator2) FactoryMethod() Product {
    	return &ConcreteProduct2{} // Cria Produto concreto B
    }
    
    func main() {
    	// Exemplo de uso
    	creator1 := &ConcreteCreator1{}
    	fmt.Println(creator1.SomeOperation())
    
    	creator2 := &ConcreteCreator2{}
    	fmt.Println(creator2.SomeOperation())
    }
    
  • Fábrica abstrata (Abstract Factory): Fornece uma interface para criar famílias de objetos relacionados ou dependentes sem especificar suas classes concretas.

    package main
    
    import "fmt"
    
    // Interface do produto A
    type AbstractProductA interface {
    	UseProductA() string
    }
    
    // Produto A1 concreto
    type ConcreteProductA1 struct{}
    
    func (*ConcreteProductA1) UseProductA() string {
    	return "O resultado do produto A1."
    }
    
    // Produto A2 concreto
    type ConcreteProductA2 struct{}
    
    func (*ConcreteProductA2) UseProductA() string {
    	return "O resultado do produto A2."
    }
    
    // Interface do produto B
    type AbstractProductB interface {
    	UseProductB() string
    	AnotherFunctionB(collaborator AbstractProductA) string // Interação com produto A
    }
    
    // Produto B1 concreto
    type ConcreteProductB1 struct{}
    
    func (*ConcreteProductB1) UseProductB() string {
    	return "O resultado do produto B1."
    }
    
    // Interação B1 com qualquer tipo de AbstractProductA
    func (*ConcreteProductB1) AnotherFunctionB(collaborator AbstractProductA) string {
    	result := collaborator.UseProductA()
    	return fmt.Sprintf("O resultado do B1 colaborando com o (%s)", result)
    }
    
    // Produto B2 concreto
    type ConcreteProductB2 struct{}
    
    func (*ConcreteProductB2) UseProductB() string {
    	return "O resultado do produto B2."
    }
    
    // Interação B2 com qualquer tipo de AbstractProductA
    func (*ConcreteProductB2) AnotherFunctionB(collaborator AbstractProductA) string {
    	result := collaborator.UseProductA()
    	return fmt.Sprintf("O resultado do B2 colaborando com o (%s)", result)
    }
    
    // Interface da fábrica abstrata
    type AbstractFactory interface {
    	CreateProductA() AbstractProductA
    	CreateProductB() AbstractProductB
    }
    
    // Fábrica concreta 1
    type ConcreteFactory1 struct{}
    
    func (*ConcreteFactory1) CreateProductA() AbstractProductA {
    	return &ConcreteProductA1{}
    }
    
    func (*ConcreteFactory1) CreateProductB() AbstractProductB {
    	return &ConcreteProductB1{}
    }
    
    // Fábrica concreta 2
    type ConcreteFactory2 struct{}
    
    func (*ConcreteFactory2) CreateProductA() AbstractProductA {
    	return &ConcreteProductA2{}
    }
    
    func (*ConcreteFactory2) CreateProductB() AbstractProductB {
    	return &ConcreteProductB2{}
    }
    
    // Código cliente que trabaja con la fábrica
    func ClientCode(factory AbstractFactory) {
    	productA := factory.CreateProductA()
    	productB := factory.CreateProductB()
    
    	fmt.Println(productB.UseProductB())
    	fmt.Println(productB.AnotherFunctionB(productA))
    }
    
    func main() {
    	fmt.Println("Cliente: Probando código cliente con el primer tipo de fábrica:")
    	ClientCode(&ConcreteFactory1{})
    
    	fmt.Println("Cliente: Probando el mismo código cliente con el segundo tipo de fábrica:")
    	ClientCode(&ConcreteFactory2{})
    }
    

A principal diferença entre o método de fábrica e a fábrica abstrata: O método de fábrica cria produtos individuais, enquanto que a fábrica abstrata cria famílias de produtos.

Nome do padrão Descrição Quando usar
Fábrica simples Método numa classe para criar objetos de diferentes tipos. Para criar objetos simples sem necessidade de uma hierarquia de fábricas.
Método de fábrica Interface para criar um objeto, permitindo que subclasses decidam qual classe instanciar. Quando uma classe não consegue prever o tipo de objetos que deve criar.
Fábrica abstrata Interface para criar famílias de objetos relacionados. Quando o sistema deve ser independente do modo como seus produtos são criados e representados.

O padrão Fábrica promove um baixo acoplamento do código e facilita a adição de novos tipos de produtos sem modificar o código cliente.