Menu
Coddy logo textTech

Паттерн Abstract Factory

Часть раздела Объектно-ориентированное программирование путешествия по GO на Coddy. Урок 88 из 107.

Паттерн Abstract Factory расширяет паттерн factory, создавая семейства связанных объектов без указания их конкретных типов. Вместо одной factory function вы определяете factory interface, который реализуют несколько конкретных factory, каждая из которых создаёт согласованный набор связанных объектов.

Рассмотрим набор инструментов пользовательского интерфейса, которому необходимо создавать кнопки и флажки. Разным операционным системам требуются разные реализации, но компоненты должны согласованно работать вместе:

type Button interface {
    Render() string
}

type Checkbox interface {
    Check() string
}

// Интерфейс абстрактной фабрики
type GUIFactory interface {
    CreateButton() Button
    CreateCheckbox() Checkbox
}

Каждая конкретная фабрика производит семейство связанных компонентов:

// Семейство 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{} }

// Семейство 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{} }

Клиентский код работает с интерфейсом factory, оставаясь независимым от конкретных реализаций:

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

Используйте Abstract Factory, когда вашей системе необходимо работать с несколькими семействами связанных продуктов и вы хотите гарантировать совместное использование компонентов из одного семейства. Он сложнее, чем простой Factory, поэтому обращайтесь к нему только тогда, когда вам действительно нужно управлять семействами продуктов.

challenge icon

Задание

Легко

Давайте создадим систему мебельного магазина с использованием паттерна Abstract Factory! Вы создадите фабрики, которые производят семейства связанных предметов мебели: каждая фабрика производит единый стиль (Modern или Vintage), обеспечивая эстетическое соответствие стульев и столов, созданных одной фабрикой.

Вы организуете свой код в трёх файлах:

  • furniture.go: Define интерфейсы продуктов и конкретные типы мебели.

    Создайте два интерфейса продуктов:

    • Chair с методом SitOn() string
    • Table с методом PlaceItems() string

    Реализуйте два семейства мебели:

    • Modern family: ModernChair возвращает Sitting on a sleek modern chair, а ModernTable возвращает Placing items on a glass modern table
    • Vintage family: VintageChair возвращает Sitting on an ornate vintage chair, а VintageTable возвращает Placing items on a wooden vintage table
  • factory.go: Define ваш интерфейс абстрактной фабрики и конкретные фабрики.

    Создайте интерфейс FurnitureFactory с двумя методами:

    • CreateChair() Chair
    • CreateTable() Table

    Реализуйте две конкретные фабрики:

    • ModernFactory, которая производит ModernChair и ModernTable
    • VintageFactory, которая производит VintageChair и VintageTable

    Также создайте функцию GetFactory(style string) FurnitureFactory, которая возвращает appropriate фабрику на основе стиля (modern или vintage). Для нераспознанных стилей используйте ModernFactory по умолчанию.

  • main.go: Используйте свои фабрики, чтобы обставлять комнаты.

    Создайте функцию FurnishRoom(factory FurnitureFactory) string, которая использует фабрику для создания стула и стола, а затем возвращает formatted строку, отображающую оба действия в отдельных строках.

    Считайте введённый стиль, получите appropriate фабрику, обставьте комнату и выведите результат.

Будут предоставлены следующие входные данные:

  • Строка 1: стиль мебели (modern, vintage или что-либо другое)

Например, если введено:

modern

Ваш вывод должен быть таким:

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

А если введено:

vintage

Ваш вывод должен быть таким:

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

А если введено:

rustic

Ваш вывод должен быть таким:

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

Обратите внимание, как функция FurnishRoom работает с любой фабрикой через интерфейс. Она не знает, создаёт ли modern или vintage мебель. Это гарантирует, что вся мебель в комнате поступает из одного family, сохраняя единый стиль!

Попробуйте сами

package main

import "fmt"

// FurnishRoom использует фабрику для создания мебели и возвращает результат
// TODO: Реализуйте эту функцию
// - Используйте фабрику для создания стула и стола
// - Верните строку с результатом SitOn() на первой строке и результатом PlaceItems() на второй строке
func FurnishRoom(factory FurnitureFactory) string {
	// TODO: Создайте стул и стол с помощью фабрики
	// TODO: Верните отформатированную строку с обоими действиями на отдельных строках
	return ""
}

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

	// TODO: Получите соответствующую фабрику на основе стиля
	// TODO: Обставьте комнату с помощью фабрики
	// TODO: Выведите результат
}
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование

Потренируйтесь самостоятельно: Онлайн-компилятор Go