TGStat
TGStat
Введите текст для поиска
Расширенный поиск каналов
  • Язык сайта
    flag Russian flag English flag Uzbek
  • Вход на сайт
  • Каталог
    Каталог каналов и чатов Региональные подборки Тематические подборки Платные каналы Поиск каналов
    Добавить канал/чат
  • Рейтинги
    Рейтинг каналов Рейтинг чатов Рейтинг публикаций
    Рейтинги брендов и персон
  • Аналитика
  • Поиск по публикациям
  • Мониторинг Telegram
  • Продвижение
    Реклама через Яндекс Бизнес Реклама в каналах через TGStat Agency Реклама на сайте TGStat.ru
Николай Тузов

28 Aug 2024, 22:24

Открыть в Telegram Поделиться Пожаловаться

Паттерн Functional Options

Этот подход также порой может называться Option Pattern, OptFunc, Config Fucation и т.п., зависит от фантазии ваших коллег 🙃

Да, как мы знаем, опциональные аргументы Go не поддерживает, но можно делать так:

func SendNotification(userID string, msg string, opts ...OptionFunc)

Вместо добавления множества параметров, мы передаем один или несколько опциональных параметров (опций), в виде variadic-аргументов — opts.

Ниже мы ещё разберёмся как это работает, но давайте сначала посмотрим как этим пользоваться. Теперь вызовы будут выглядеть таким образом:

// С отправкой СМС, но без Email и без указания приоритета
SendNotification(userID, myMessage, WithSMS())

// С отправкой Email и с указанным приоритетом6
SendNotification(userID, myMessage, WithEmail(), WithPriority(HighPriority))

// И без всего этого:
SendNotification(userID, myMessage)

Что нам это даёт:

- Не надо рефакторить уже имеющиеся вызовы, они останутся без изменений
- Вызовы функций менее громоздкие, когда весь набор опций требуется очень редко, либо никогда
- Этот подход популярный и узнаваемый, а значит ваш опытный коллега сразу поймёт суть, лишь окинув ваш код быстрым взглядом.
- Моё субъективное мнение — это удобно, красиво и интуитивно понятно. Но тут вы можете со мной не согласиться, это нормально
- Параметры становятся будто бы именованными, сравните:

(true, false, "high", "important", ...)

и

(WithSMS(), WithEmail(), WithPriority("high"), WithTitle("important"), ...)

В первом случае вы можете лишь догадываться, какой параметр что означает, во втором сразу видите что есть что

Но есть и минусы — нужно написать чуть больше кода, и когда таких With() становится много, выглядит это даже более громоздко, чем раньше. То есть, если в большинстве вызовов вам приходится передавать много подобных опций, то, скорее всего, это не ваш вариант.

Если вам это не подходит, есть и другие варианты, например:

- Передавать вместо набора параметров одну структуру (такой подход используется в aws-sdk-go)
- Использовать отдельные функции для разных типов вызовов и др. О них я могу рассказать отдельно, но они более простые и очевидные.

Реализация

Сначала описываем тип OptionFunc и несколько функций, которые задают определенные параметры:

type OptionFunc func(*Notification)

func WithEmail() OptionFunc {
return func(n *Notification) {
n.SendEmail = true
}
}

func WithSMS() OptionFunc {
return func(n *Notification) {
n.SendSMS = true
}
}

func WithPriority(priority string) OptionFunc {
return func(n *Notification) {
n.Priority = priority
}
}

Теперь учим нашу функцию SendNotification() применять всё это:

func SendNotification(userID string, msg string, opts ...OptionFunc) {
// Создаем уведомление с базовыми параметрами
notification := &Notification{
UserID: userID,
Message: message,
}

// Применяем опции
for _, opt := range opts {
opt(notification)
}

// Отправляем уведомление
send(notification)
}

Здесь можете посмотреть рабочий пример и поиграться с ним. И также я скину исходный код этого примера в комментарии к этому посту, чтобы не потерялось.

Я встречал этот паттерн во всех компаниях, в которых писал код на Go, и мне он очень хорошо зашел. И даже если он вам не нравится, сталкиваться вы с ним будете часто, поэтому понимать что это и зачем точно стоит.

В комментариях предлагаю обсудить — нравится ли вам такое решение, и почему.
Сразу предупреждаю
— агрессивные, неконструктивные, надменные и прочие комментарии я буду удалять, а в некоторых случаях банить авторов. Давайте вести профессиональную и конструктивную дискуссию, без оскорблений и эмоций.

#guide #pattern

11.3k 4 221 63 253
Каталог
Каталог каналов и чатов Подборки каналов Поиск каналов Добавить канал/чат
Рейтинги
Рейтинг каналов Telegram Рейтинг чатов Telegram Рейтинг публикаций Рейтинги брендов и персон
API
API статистики API поиска публикаций API Callback
Наши каналы
@TGStat @TGStat_Chat @telepulse @TGStatAPI
Почитать
Академия TGStat Исследование Telegram 2019 Исследование Telegram 2021 Исследование Telegram 2023
Контакты
Справочный центр Поддержка Почта Вакансии
Всякая всячина
Пользовательское соглашение Политика конфиденциальности Публичная оферта
Наши боты
@TGStat_Bot @SearcheeBot @TGAlertsBot @tg_analytics_bot @TGStatChatBot