Продолжаем знакомиться с этой книгой, и сегодня хочу написать про второе правило внедрения DDD в приложение: всегда держите валидное состояние в памяти в одном месте.
Это значит, что вся логика работы с доменом должна быть определена в отдельном пакете и скрыта от других пакетов. Менять состояние домена должно только публичное API. Автор также не советует создавать геттеры и сеттеры.
Возвращаясь к нашему примеру с тренажерным залом из вчерашнего поста, инкапсулируем домен Hour:
type Hour struct {
hour time.Time
availability Availability
}
// ...
func NewAvailableHour(hour time.Time) (*Hour, error) {
if err := validateTime(hour); err != nil {
return nil, err
}
return &Hour{
hour: hour,
availability: Available,
}, nil
}
Плохой пример использования этого домена, порождающий большое количество веток условий:
h := hour.NewAvailableHour("13:00")
if h.HasTrainingScheduled() {
h.SetState(hour.Available)
} else {
return some error
}
и хороший пример:
func (h *Hour) CancelTraining() error {
if !h.HasTrainingScheduled() {
return some error
}
h.availability. Available
return nil
}
h := hour.NewAvailableHour("13:00")
if err := h.CancelTraining(); err != nil {
return err
}
Вся работа с доменом - только в пакете с доменом, никакая логика по установке каких-либо состояний не выносится наружу.