Назад к вопросам
Middle
110
questionbank

Расскажи о паттерне Фабрика (Factory).

Sobes Copilot

Получайте ответы в реальном времени

Ответ от нейросети

sobes.tech AI

Фабрика — это порождающий паттерн проектирования, который предоставляет общий интерфейс для создания объектов в суперклассе, в то время как подклассы могут изменять тип создаваемых объектов.

  • Простая фабрика (Simple Factory): Не является паттерном в чистом виде, скорее идиома. Класс с методом, который создает объекты, исходя из входных параметров.

    package main
    
    import "fmt"
    
    type Product interface {
    	Use()
    }
    
    type ConcreteProductA struct{}
    
    func (p *ConcreteProductA) Use() {
    	fmt.Println("Using Concrete Product A")
    }
    
    type ConcreteProductB struct{}
    
    func (p *ConcreteProductB) Use() {
    	fmt.Println("Using Concrete Product 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()
    }
    
  • Фабричный метод (Factory Method): Определяет интерфейс для создания объекта, но позволяет подклассам решать, какой класс инстанцировать.

    package main
    
    import "fmt"
    
    // Интерфейс продукта
    type Product interface {
    	Operation() string
    }
    
    // Конкретный продукт A
    type ConcreteProduct1 struct{}
    
    func (p *ConcreteProduct1) Operation() string {
    	return "Result of the ConcreteProduct1"
    }
    
    // Конкретный продукт B
    type ConcreteProduct2 struct{}
    
    func (p *ConcreteProduct2) Operation() string {
    	return "Result of the ConcreteProduct2"
    }
    
    // Интерфейс создателя
    type Creator interface {
    	FactoryMethod() Product
    	SomeOperation() string
    }
    
    // Базовая структура создателя
    type BaseCreator struct{}
    
    func (bc *BaseCreator) SomeOperation() string {
    	// Вызов фабричного метода для получения объекта продукта
    	product := bc.FactoryMethod()
    	// Использование продукта
    	result := "Creator: The same creator's code has just worked with " + product.Operation()
    	return result
    }
    
    // Конкретный создатель A
    type ConcreteCreator1 struct {
    	BaseCreator
    }
    
    func (cc *ConcreteCreator1) FactoryMethod() Product {
    	return &ConcreteProduct1{} // Создает Конкретный продукт A
    }
    
    // Конкретный создатель B
    type ConcreteCreator2 struct {
    	BaseCreator
    }
    
    func (cc *ConcreteCreator2) FactoryMethod() Product {
    	return &ConcreteProduct2{} // Создает Конкретный продукт B
    }
    
    func main() {
    	// Пример использования
    	creator1 := &ConcreteCreator1{}
    	fmt.Println(creator1.SomeOperation())
    
    	creator2 := &ConcreteCreator2{}
    	fmt.Println(creator2.SomeOperation())
    }
    
    
  • Абстрактная фабрика (Abstract Factory): Предоставляет интерфейс для создания семейств связанных или зависимых объектов без указания их конкретных классов.

    package main
    
    import "fmt"
    
    // Интерфейс продукт A
    type AbstractProductA interface {
    	UseProductA() string
    }
    
    // Конкретный продукт A1
    type ConcreteProductA1 struct{}
    
    func (*ConcreteProductA1) UseProductA() string {
    	return "The result of the product A1."
    }
    
    // Конкретный продукт A2
    type ConcreteProductA2 struct{}
    
    func (*ConcreteProductA2) UseProductA() string {
    	return "The result of the product A2."
    }
    
    // Интерфейс продукт B
    type AbstractProductB interface {
    	UseProductB() string
    	AnotherFunctionB(collaborator AbstractProductA) string // Взаимодействие с продуктом A
    }
    
    // Конкретный продукт B1
    type ConcreteProductB1 struct{}
    
    func (*ConcreteProductB1) UseProductB() string {
    	return "The result of the product B1."
    }
    
    // Взаимодействие B1 с любым типом AbstractProductA
    func (*ConcreteProductB1) AnotherFunctionB(collaborator AbstractProductA) string {
    	result := collaborator.UseProductA()
    	return fmt.Sprintf("The result of the B1 collaborating with the (%s)", result)
    }
    
    // Конкретный продукт B2
    type ConcreteProductB2 struct{}
    
    func (*ConcreteProductB2) UseProductB() string {
    	return "The result of the product B2."
    }
    
    // Взаимодействие B2 с любым типом AbstractProductA
    func (*ConcreteProductB2) AnotherFunctionB(collaborator AbstractProductA) string {
    	result := collaborator.UseProductA()
    	return fmt.Sprintf("The result of the B2 collaborating with the (%s)", result)
    }
    
    // Интерфейс абстрактной фабрики
    type AbstractFactory interface {
    	CreateProductA() AbstractProductA
    	CreateProductB() AbstractProductB
    }
    
    // Конкретная фабрика 1
    type ConcreteFactory1 struct{}
    
    func (*ConcreteFactory1) CreateProductA() AbstractProductA {
    	return &ConcreteProductA1{}
    }
    
    func (*ConcreteFactory1) CreateProductB() AbstractProductB {
    	return &ConcreteProductB1{}
    }
    
    // Конкретная фабрика 2
    type ConcreteFactory2 struct{}
    
    func (*ConcreteFactory2) CreateProductA() AbstractProductA {
    	return &ConcreteProductA2{}
    }
    
    func (*ConcreteFactory2) CreateProductB() AbstractProductB {
    	return &ConcreteProductB2{}
    }
    
    // Клиентский код, работающий с фабрикой
    func ClientCode(factory AbstractFactory) {
    	productA := factory.CreateProductA()
    	productB := factory.CreateProductB()
    
    	fmt.Println(productB.UseProductB())
    	fmt.Println(productB.AnotherFunctionB(productA))
    }
    
    func main() {
    	fmt.Println("Client: Testing client code with the first factory type:")
    	ClientCode(&ConcreteFactory1{})
    
    	fmt.Println("Client: Testing the same client code with the second factory type:")
    	ClientCode(&ConcreteFactory2{})
    }
    
    

Главное различие между Фабричным методом и Абстрактной фабрикой: Фабричный метод создает одиночные продукты, тогда как Абстрактная фабрика создает семейства продуктов.

Название паттерна Описание Когда использовать
Простая фабрика Метод в одном классе для создания объектов разных типов. Для простого создания объектов без необходимости иерархии фабрик.
Фабричный метод Интерфейс для создания объекта, позволяющий подклассам решать, какой класс инстанцировать. Когда класс не может предсказать тип объектов, которые он должен создать.
Абстрактная фабрика Интерфейс для создания семейств связанных объектов. Когда система должна быть независима от способа создания и представления ее продуктов.

Паттерн Фабрика способствует слабой связанности кода и облегчает добавление новых типов продуктов без изменения клиентского кода.