Какие знаешь паттерны проектирования?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
# Обзор паттернов проектирования в Go
Да, как разработчик с глубоким опытом в Go, я знаю множество паттернов проектирования, которые активно применяются в проектах. Go, несмотря на свою простоту и прагматичность, прекрасно адаптирует классические паттерны, часто с особенностями, обусловленными его уникальными чертами: интерфейсами, композицией вместо наследования, и акцентом на явное поведение над сложной структурой.
Ключевые категории паттернов в Go
Паттерны создания объектов
-
Singleton(Одиночка): В Go реализуется через глобальные переменные или с использованиемsync.Onceдля безопасного создания в многопоточной среде. Часто применяется для логгеров, конфигураций, пулов соединений.type Database struct { conn string } var instance *Database var once sync.Once func GetInstance() *Database { once.Do(func() { instance = &Database{conn: "postgres"} }) return instance } -
Factory(Фабрика): Используется для создания объектов без явного указания их точного типа. Часто реализуется через функции или интерфейсы.type Vehicle interface { Drive() } func NewVehicle(type string) Vehicle { switch type { case "car": return &Car{} case "bike": return &Bike{} } return nil } -
Builder(Строитель): Полезен для создания сложных объектов с множеством опциональных параметров. В Go часто реализуется через структуру-конфигуратор (Config struct) или методWithOption.type Server struct { host string; port int } type ServerBuilder struct { server Server } func (sb *ServerBuilder) Host(h string) *ServerBuilder { sb.server.host = h; return sb } func (sb *ServerBuilder) Build() Server { return sb.server }
Структурные паттерны
-
Composite(Композиция): Это естественный паттерн для Go, где композиция является основным способом построения типов. Объекты включают другие объекты, реализующие общий интерфейс.type Graphic interface { Draw() } type Picture struct { children []Graphic } func (p *Picture) Draw() { for _, child := range p.children { child.Draw() } } -
Adapter(Адаптер): Один из самых популярных паттернов. Интерфейсы Go позволяют легко адаптировать внешние типы к требуемому интерфейсу системы.type OldSystem struct {} func (o *OldSystem) LegacyCall() {} type NewInterface interface { Call() } type Adapter struct { old *OldSystem } func (a *Adapter) Call() { a.old.LegacyCall() } -
Decorator(Декоратор): Реализуется через композицию интерфейсов и промежуточные структуры, которые добавляют поведение. Часто используется для middleware в веб-серверах.type Handler interface { Handle(req Request) } type LoggingDecorator struct { wrapped Handler } func (d *LoggingDecorator) Handle(req Request) { log.Println("start"); d.wrapped.Handle(req); log.Println("end") }
Паттерны поведения
-
Strategy(Стратегия): Идеально воплощается через интерфейсы. Позволяет заменять алгоритмы или поведение в runtime.type PaymentStrategy interface { Pay(amount float64) } func ProcessOrder(amount float64, strategy PaymentStrategy) { strategy.Pay(amount) } -
Observer/Publisher-Subscriber: В Go часто реализуется через каналы (channels) и горутины (goroutines). Каждый подписчик получает свой канал, в который publisher отправляет события.type Event struct { Data string } type Subscriber chan Event func (p *Publisher) Subscribe() Subscriber { ch := make(Subscriber); p.subs[ch] = ch; return ch } -
Command(Команда): Объект, представляющий действие. В Go это часто функция или интерфейсCommand, который можно хранить в очереди или передавать.type Command interface { Execute() } type Button struct { command Command } func (b *Button) Click() { b.command.Execute() }
Go-специфичные и идиоматические подходы
Go также развил свои собственные идиоматические паттерны, которые заменяют или дополняют классические:
-
Functional Options: Паттерн для конфигурации сложных структур вместо классического Builder. Позволяет создавать чистый, расширяемый API.type ServerOpt func(*Server) func WithPort(port int) ServerOpt { return func(s *Server) { s.port = port } } func NewServer(opts ...ServerOpt) *Server { s := &Server{port: 8080} for _, opt := range opts { opt(s) } return s } -
Middleware: Крайне важный паттерн для веб-разработки (например, вnet/http). Это последовательность обработчиков, каждый из которых оборачивает следующий (применение Decorator). -
Context(context.Context): Не является классическим паттерном, но представляет мощный инструмент для передачи данных, управления временем жизни и cancellation в цепочках вызовов, особенно в concurrent-коде. -
Worker Pool/Pipeline: Использует каналы и горутины для организации параллельной обработки данных, что является адаптацией паттернов Producer-Consumer и Pipeline.
Выбор паттернов в Go
Применение паттернов в Go следует принципу прагматичности:
- Используйте простые интерфейсы для Strategy, Adapter.
- Используйте композицию и агрегацию вместо сложных иерархий.
- Каналы и горутины — ваши лучшие инструменты для Observer, Pipeline, Worker Pool.
- Часто достаточно простой функции или структуры с методами, без формального внедрения классического паттерна.
Знание этих паттернов позволяет создавать в Go чистый, поддерживаемый, эффективный и легко тестируемый код, который хорошо масштабируется и адаптируется к изменению требований. Главное — применять их осознанно, когда они решают конкретную проблему архитектуры, а не как обязательное украшение кода.