Menu
Coddy logo textTech

Паттерн Factory

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

Паттерн Factory делегирует создание объектов отдельной функции или методу, позволяя создавать экземпляры без раскрытия логики создания. В отличие от Singleton, который контролирует количество экземпляров, Factory сосредоточен на гибком создании объектов на основе входных параметров.

В Go factory обычно представляет собой function, которая возвращает interface type, позволяя создавать разные конкретные типы через единый API:

type Notifier interface {
    Send(message string) string
}

type EmailNotifier struct{}
type SMSNotifier struct{}

func (e EmailNotifier) Send(message string) string {
    return "Email: " + message
}

func (s SMSNotifier) Send(message string) string {
    return "SMS: " + message
}

func NewNotifier(notifierType string) Notifier {
    switch notifierType {
    case "email":
        return EmailNotifier{}
    case "sms":
        return SMSNotifier{}
    default:
        return EmailNotifier{}
    }
}

Фабричная функция NewNotifier инкапсулирует решение о том, какой конкретный тип создать. Клиентский код работает только с интерфейсом Notifier, не зная о конкретной реализации:

notifier := NewNotifier("sms")
result := notifier.Send("Hello!")  // "SMS: Hello!"

Этот шаблон особенно полезен, когда вам нужно create объекты на основе условий времени выполнения, вы хотите централизовать сложную логику инициализации или вам нужно легко добавлять новые типы без изменения клиентского кода. Просто добавьте новую struct, реализующую interface, и обновите factory function.

challenge icon

Задание

Легко

Давайте создадим систему преобразования document с использованием паттерна Factory! Вы создадите factory, которая производит различные преобразователи document на основе целевого format, позволяя клиентскому коду работать с любым преобразователем через единый interface.

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

  • converter.go: Define ваш interface converter и конкретные реализации.

    Create interface Converter с method Convert(content string) string, который принимает content document и возвращает преобразованный результат.

    Implement три типа converter:

    • PDFConverter: его Convert method возвращает PDF: [content]
    • HTMLConverter: его Convert method возвращает HTML: <p>[content]</p>
    • MarkdownConverter: его Convert method возвращает MD: # [content]

    Create factory function NewConverter(format string) Converter, которая возвращает соответствующий converter на основе строки format (pdf, html или markdown). Для любого нераспознанного format верните PDFConverter как значение default.

  • main.go: Используйте свою factory для создания converter и обработки document.

    Read тип format и content document. Используйте factory для создания соответствующего converter, затем преобразуйте content и выведите result.

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

  • Строка 1: тип Format (pdf, html, markdown или что-то ещё)
  • Строка 2: content document для преобразования

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

html
Welcome to Go Programming

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

HTML: <p>Welcome to Go Programming</p>

А если дано:

markdown
Chapter One

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

MD: # Chapter One

А если дано:

pdf
Annual Report 2024

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

PDF: Annual Report 2024

А если дано:

docx
Meeting Notes

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

PDF: Meeting Notes

Обратите внимание, что main-коду не нужно знать о конкретных типах converter. Он просто запрашивает converter у factory и использует interface. Благодаря этому позже легко добавлять новые format без изменения клиентского кода!

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

package main

import (
	"bufio"
	"fmt"
	"os"
)

func main() {
	scanner := bufio.NewScanner(os.Stdin)
	
	// Прочитать тип формата
	scanner.Scan()
	format := scanner.Text()
	
	// Прочитать содержимое документа
	scanner.Scan()
	content := scanner.Text()
	
	// TODO: Использовать фабрику для создания соответствующего конвертера
	// TODO: Преобразовать содержимое и вывести результат
	
	fmt.Println(result)
}
quiz iconПроверьте себя

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

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

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