Что это такое
Паттерн Factory Method (фабричный метод) прячет создание объекта за функцией. Вызывающий код говорит, что ему нужно, — а фабрика решает, какой конкретный тип создать, и возвращает его как интерфейс.
Вызывающий код никогда не работает с конкретными типами напрямую, поэтому новые виды можно добавлять, не меняя код вызова. В Go это просто функция NewSomething(), которая возвращает интерфейс.
Пример: фабрика хранилищ
NewStorage("disk") и NewStorage("memory") возвращают разные конкретные типы за одним и тем же интерфейсом Storage — вызывающий код не видит разницы, и она ему не нужна.
Фабрика выбирает тип
Переключение по видам находится в одном месте — в фабрике. Остальная часть программы знает только про интерфейс.
Вывод: программа на Go и захваченный вывод
package main
import "fmt"
type Storage interface {
Save(data string) string
}
type DiskStore struct{}
func (DiskStore) Save(d string) string { return "диск: сохранён " + d }
type MemoryStore struct{}
func (MemoryStore) Save(d string) string { return "память: хранится " + d }
// Фабрика решает, какой конкретный тип создать.
func NewStorage(kind string) Storage {
switch kind {
case "memory":
return MemoryStore{}
default:
return DiskStore{}
}
}
func main() {
for _, kind := range []string{"disk", "memory"} {
s := NewStorage(kind)
fmt.Println(s.Save("заказ №1042"))
}
}
Когда его применять
Применяйте, когда конкретный тип зависит от того, что известно только во время выполнения — от значения конфигурации, выбора пользователя, окружения, — или когда вы хотите держать логику создания ровно в одном месте.
Не применяйте, когда реализация всего одна и вторая не предвидится. Для store := DiskStore{} фабрика не нужна.
Плюсы и минусы
Плюсы: логика создания в одном месте; вызывающий код зависит только от интерфейса; добавление нового вида затрагивает только фабрику.
Минусы: ещё один слой, который приходится читать; при единственной реализации это чистая формальность.