← Назад к вопросам

Какие знаешь паттерны проектирования?

2.0 Middle🔥 181 комментариев
#Микросервисы и архитектура

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI5 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

# Обзор паттернов проектирования в 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 чистый, поддерживаемый, эффективный и легко тестируемый код, который хорошо масштабируется и адаптируется к изменению требований. Главное — применять их осознанно, когда они решают конкретную проблему архитектуры, а не как обязательное украшение кода.

Какие знаешь паттерны проектирования? | PrepBro