> Какие группы паттернов проектирования существуют (Go)
Уровень: senior · Роль: backend · Язык: Go · Категория: Технические вопросы
Компании: Wildberries
Стек: Go
> Пример ответа
Короткий ответ
Существует три классические группы паттернов проектирования: порождающие (creational), структурные (structural) и поведенческие (behavioral). Порождающие отвечают за создание объектов, структурные - за композицию классов и объектов, поведенческие - за взаимодействие и распределение ответственности между объектами. В Go часто используются функциональные опции, синглтон через sync.Once, стратегия через функции, а также конвейеры для обработки данных.
Подробное объяснение
Классификация паттернов основана на книге "Банды четырёх" (GoF) и остаётся актуальной для любого языка, включая Go.
Порождающие паттерны решают задачу гибкого создания объектов, скрывая логику инстанцирования. В Go это особенно важно из-за отсутствия конструкторов и наследования. Типичные представители: singleton, factory method, abstract factory, builder, prototype. В Go синглтон реализуется через sync.Once, а builder часто заменяется функциональными опциями.
Структурные паттерны определяют, как классы и объекты собираются в более крупные структуры, обеспечивая гибкость и расширяемость. Сюда входят adapter, facade, decorator, proxy, composite, bridge, flyweight. В Go из-за интерфейсов и композиции вместо наследования многие структурные паттерны упрощаются: adapter - это просто функция, преобразующая один интерфейс в другой, decorator - обёртка через замыкания.
Поведенческие паттерны описывают способы взаимодействия между объектами и распределение обязанностей. Это strategy, observer, command, iterator, state, template method, chain of responsibility, mediator, memento, visitor. В Go стратегия часто реализуется как поле-функция, observer - через каналы, command - через замыкания.
Важно понимать, что Go в силу своей простоты и отсутствия наследования требует адаптации классических паттернов. Многие из них становятся избыточными, а вместо них используются идиомы языка: goroutines, channels, context.Context, sync.Once, функциональные опции.
На практике
Для senior-позиции важно не просто перечислить группы, а показать понимание, когда паттерн уместен, а когда - нет. В Go часто встречается антипаттерн "over-engineering": попытка применить классический паттерн GoF там, где достаточно простой функции.
Практические рекомендации:
- Порождающие паттерны в Go обычно сводятся к конструкторам вида
NewX()и функциональным опциям. - Структурные паттерны часто заменяются интерфейсами и композицией - это естественный способ для Go.
- Поведенческие паттерны хорошо ложатся на каналы и горутины, особенно observer и pipeline.
- Для конкурентного доступа используйте
sync.Onceвместо синглтона с ручной синхронизацией. - Не создавайте иерархии классов - в Go нет наследования, используйте интерфейсы.
Пример кода
Порождающий паттерн - функциональные опции:
GOtype Server struct {port inttimeout time.Duration}type Option func(*Server)func WithPort(p int) Option {return func(s *Server) { s.port = p }}func WithTimeout(t time.Duration) Option {return func(s *Server) { s.timeout = t }}func NewServer(opts ...Option) *Server {s := &Server{port: 8080, timeout: 5 * time.Second}for _, opt := range opts {opt(s)}return s}
Структурный паттерн - adapter через функцию:
GOtype Handler interface {Handle(ctx context.Context, req Request) Response}type HandlerFunc func(ctx context.Context, req Request) Responsefunc (f HandlerFunc) Handle(ctx context.Context, req Request) Response {return f(ctx, req)}
Поведенческий паттерн - strategy через поле-функцию:
GOtype Sorter struct {compare func(a, b int) bool}func (s *Sorter) Sort(data []int) {sort.Slice(data, func(i, j int) bool {return s.compare(data[i], data[j])})}
Как отвечать на собеседовании
Начните с чёткого перечисления трёх групп и их назначения. Затем покажите, как паттерны адаптируются под Go: отсутствие наследования, интерфейсы, функции как значения, каналы. Приведите конкретные примеры из своей практики - это сильный сигнал для senior.
Структура ответа:
- Назовите группы и их цель.
- Приведите по одному примеру из каждой группы в Go.
- Объясните, когда паттерн полезен, а когда - избыточен.
- Упомяните идиомы Go, заменяющие классические паттерны.
Если интервьюер спрашивает про конкретный паттерн, сначала опишите проблему, которую он решает, затем реализацию в Go, затем trade-off.
Что проверяет интервьюер
Интервьюер оценивает:
- Базовое знание классификации GoF.
- Понимание, как особенности языка влияют на реализацию паттернов.
- Умение отличать паттерн от антипаттерна.
- Практический опыт: может ли кандидат привести реальный пример из кода.
- Способность рассуждать о trade-off: когда паттерн оправдан, а когда усложняет код.
- Глубину: senior должен знать, что в Go многие паттерны упрощаются или заменяются идиомами.
Типичные ошибки
- Перечисление паттернов без объяснения, какую проблему они решают.
- Механическое перенесение классических реализаций из Java/C++ в Go без учёта особенностей языка.
- Утверждение, что паттерны - это серебряная пуля, и их нужно применять всегда.
- Игнорирование идиом Go: функциональные опции,
sync.Once, каналы. - Путаница между паттернами: например, путают strategy и state, adapter и facade.
- Отсутствие примеров из реальной практики - для senior это критично.
- Чрезмерное усложнение ответа: попытка рассказать все паттерны сразу вместо структурированного ответа.
> Похожие задачи по Go
Как избежать гонок и рейсов в базе данных
Для чего нужен брокер сообщений Kafka
В чем разница между фабрикой и обычным конструктором
Почему в Go нельзя взять значение по ссылке из мапы
> Похожие задачи по backend
Как избежать гонок и рейсов в базе данных
Для чего нужен брокер сообщений Kafka
В чем разница между фабрикой и обычным конструктором
Почему в Go нельзя взять значение по ссылке из мапы
> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?
Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью