Реализация статусов и списков
Enum
(на iota)
type Status int
const (
Free Status = iota
Busy
)
func (r Status) String() string {
return [...]string{"Free", "Busy"}[r]
}Enum
(на строках)
Реализация:
package basket
// Status — тип для статусов
type Status string
const (
StatusEmpty Status = ""
StatusCreated Status = "created"
StatusConfirmed Status = "confirmed"
)
// Методы для статуса
func (s Status) Equals(other Status) bool {
return s == other
}
func (s Status) IsEmpty() bool {
return s == StatusEmpty
}
func (s Status) String() string {
return string(s)
}Этот вариант дает возможность:
•Ограничить возможные значения статусов
•Использовать статусы как строки без приведения типов
•Добавлять методы для удобства работы
Пример использования:
package main
import (
"fmt"
"basket"
)
func main() {
var s basket.Status = basket.StatusCreated
if s.Equals(basket.StatusCreated) {
fmt.Println("Статус: создан")
}
if !s.IsEmpty() {
fmt.Println("Статус не пустой:", s)
}
}
Такой подход удобен, когда статусы фиксированы. А сам статус состоит только из 1 поля.
Enum
(на структуре)
Реализация:
package basket
import (
"gitlab.com/microarch-ru/basket/internal/pkg/errs"
"strings"
)
// Определение фиксированных периодов доставки
var (
Morning = newDeliveryPeriod(1, "morning", 6, 12)
Midday = newDeliveryPeriod(2, "midday", 12, 17)
Evening = newDeliveryPeriod(3, "evening", 17, 24)
Night = newDeliveryPeriod(4, "night", 0, 6)
DeliveryPeriods = []*DeliveryPeriod{Morning, Midday, Evening, Night}
)
// DeliveryPeriod — тип, представляющий период доставки
type DeliveryPeriod struct {
id int
name string
from int
to int
}
// Создание нового периода доставки
func newDeliveryPeriod(id int, name string, from int, to int) *DeliveryPeriod {
return &DeliveryPeriod{
id: id,
name: name,
from: from,
to: to,
}
}
// Методы для работы с периодами доставки
func (dp *DeliveryPeriod) Equals(other *DeliveryPeriod) bool {
return dp.id == other.id
}
func (dp *DeliveryPeriod) ID() int {
return dp.id
}
func (dp *DeliveryPeriod) Name() string {
return dp.name
}
func (dp *DeliveryPeriod) From() int {
return dp.from
}
func (dp *DeliveryPeriod) To() int {
return dp.to
}
// Получение периода по названию
func GetDeliveryPeriodByName(name string) (*DeliveryPeriod, error) {
for _, v := range DeliveryPeriods {
if strings.ToLower(v.name) == strings.ToLower(name) {
return v, nil
}
}
return nil, errs.NewObjectNotFoundError("name")
}
// Получение периода по ID
func GetDeliveryPeriodByID(id int) (*DeliveryPeriod, error) {
for _, v := range DeliveryPeriods {
if v.id == id {
return v, nil
}
}
return nil, errs.NewObjectNotFoundError("id")
}
Основные моменты:
- Фиксированные объекты
- Переменные Morning, Midday, Evening, Night являются предопределенными значениями.
- Структура DeliveryPeriod
- Содержит ID, название (name), время начала (from) и конца (to).
- Equals сравнивает два периода по id.
- Методы поиска
- GetDeliveryPeriodByName — ищет период по названию (регистр не учитывается).
- GetDeliveryPeriodByID — ищет период по ID.
Пример использования:
func main() {
period, err := basket.GetDeliveryPeriodByName("morning")
if err != nil {
fmt.Println("Период не найден")
return
}
fmt.Printf("ID: %d, Название: %s, С %d до %d\n", period.ID(), period.Name(), period.From(), period.To())
}Такой подход удобен, когда статусы фиксированы. А сам статус состоит более чем из 1 поля или нужна дополнительная бизнес логика.
Вывод
- Если нужен простой список значений, делаем простой Enum на строках.
- Если у элементов есть доп. свойства или методы, реализуем Smart Enum на структурах.
- Есть и другие варианта (iota и т.п.). Они также допустимы.