В последнее время я изучаю дизайн, управляемый предметной областью, и должен сказать, что этот тип архитектурного дизайна вызывает у меня что-то.Когда я пытаюсь применить его концепции к своему проекту Go, я сталкиваюсь с некоторыми препятствиями.Ниже приведены некоторые примеры методов, но я очень не уверен, с каким методом перейти.
Выдержка из структуры проекта:
├── api/
├── cmd/
├── internal/
| ├── base/
| | ├── eid.go
| | ├── entity.go
| | └── value_object.go
| ├── modules/
| | ├── realm/
| | | ├── api/
| | | ├── domain/
| | | | ├── realm/
| | | | | ├── service/
| | | | | ├── friendly_name.go
| | | | | ├── realm.go
| | | | | └── realm_test.go
| | | | └── other_subdomain/
| | | └── repository/
| | | ├── inmem/
| | | └── postgres/
Общая для всех методов:
package realm // import "git.int.xxxx.no/go/xxxx/internal/modules/realm/domain/realm"
// base contains common elements used by all modules
import "git.int.xxxx.no/go/xxxx/internal/base"
Метод # 1:
type Realm struct {
base.Entity
FriendlyName FriendlyName
}
type CreateRealmParams struct {
FriendlyName string
}
func CreateRealm(id base.EID, params *CreateRealmParams) (*Realm, error) {
var err error
var r = new(Realm)
r.Entity = base.NewEntity(id)
r.FriendlyName, err = NewFriendlyName(params.FriendlyName)
return r, err
}
type FriendlyName struct {
value string
}
var ErrInvalidFriendlyName = errors.New("invalid friendly name")
func (n FriendlyName) String() string { return n.value }
func NewFriendlyName(input string) (FriendlyName, error) {
if input == "" {
return ErrInvalidFriendlyName
}
// perhaps some regexp rule here...
return FriendlyName{value: input}, nil
}
С этим методом я думаю, что в долгосрочной перспективе будет много повторяющегося кода, но по крайней мере объект-значение FriendlyName является неизменным согласно требованиям DDD и открывается длядополнительные методы должны быть присоединены.
Метод # 2:
type Realm struct {
base.Entity
FriendlyName string
}
type CreateRealmParams struct {
FriendlyName string
}
func CreateRealm(id base.EID, params *CreateRealmParams) (*Realm, error) {
var err error
if err = validateFriendlyName(params.FriendlyName); err != nil {
return nil, err
}
entity := base.NewEntity(id)
return &Realm{
Entity: entity,
FriendlyName: params.FriendlyName,
}, nil
}
Это, наверное, самый распространенный пример, который я встречал там, за исключением проверки, которой не хватает во многих примерах..
Метод № 3:
type Realm struct {
base.Entity
friendlyName string
}
type CreateRealmParams struct {
FriendlyName string
}
func CreateRealm(id base.EID, params *CreateRealmParams) (*Realm, error) {
var err error
if err = validateFriendlyName(friendlyName); err != nil {
return nil, err
}
entity := base.NewEntity(id)
return &Realm{
Entity: entity,
friendlyName: friendlyName,
}, nil
}
func (r *Realm) FriendlyName() string { return r.friendlyName }
func (r *Realm) SetFriendlyName(input string) error {
if err := validateFriendlyName(input); err != nil {
return err
}
r.friendlyName = input
return nil
}
Здесь понятный тип имени - это просто строка, но неизменяемая.Эта структура напоминает мне код Java ... При поиске области должен ли уровень хранилища использовать методы установки из модели предметной области для построения агрегата области?Я пытался с реализацией DTO, помещенной в тот же пакет (dto_sql.go), который кодировал / декодировал в / из агрегата области, но это было неправильно, если поместить эту проблему в пакет домена.
Если высталкиваются с теми же проблемами, что и я, знают о любом другом методе или есть что-то, на что можно указать, мне будет очень интересно услышать от вас!