Перейти: "Статический" метод проектирования
Я ищу совет по наилучшему способу очистки следующей структуры. Я знаю, что Go не имеет статических методов, и обычно лучше инкапсулировать функциональность в отдельном пакете. Мои типы структур ссылаются друг на друга и поэтому не могут быть объявлены в отдельных пакетах из-за циклического импорта.
type Payment struct {
User *User
}
type User struct {
Payments *[]Payments
}
func (u *User) Get(id int) *User {
// Returns the user with the given id
}
func (p *Payment) Get(id int) *Payment {
// Returns the payment with the given id
}
Но, если я хочу загрузить пользователя или платеж, я просто отбрасываю получателя:
var u *User
user := u.Get(585)
Я мог бы пропустить пробелы в самих функциях, которые ставят меня нечистым:
func GetUser(id int) *User {
// Returns the user with the given id
}
func GetPayment(id int) *Payment {
// Returns the payment with the given id
}
Мне бы очень хотелось просто вызвать .Get
или подобное в структуре без написания имени структуры в самой функции. Какой идиоматический способ сделать это?
Ответы
Ответ 1
GetUser()
и GetPayment()
поражают меня как совершенно ясные и идиоматические. Я не уверен, что вы считаете нечистым о них.
Вызов .Get()
в структуре для возврата другой структуры - это то, что поражает меня как очень странное, нечеткое и унииоматическое.
Я думаю, что это может быть случай просто придерживаться идиомы и доверять тому, что вы привыкнете к ней.
Ответ 2
с функцией Get
отлично работает; это не унииоматично.
func (u *User) Get(id int) *User
не имеет никакого смысла, но должно быть func (u *User) Get(id int) error
. Единственное, чего вам не хватает, это то, что вы можете определить приемник метода на указателе, а затем внутри этого метода разыщите указатель, чтобы перезаписать то, на что он указывает.
Вот так:
// Returns the user with the given id
func (u *User) Get(id int) error {
*u = User{ ... } // dereference the pointer and assign something to it
return nil // or an error here
}
и если возникла какая-либо проблема, верните ошибку. Теперь вы можете сказать
type Getter interface {
Get(int) error
}
и поэтому может быть определен любой тип, который определяет Get(id)error
. Затем вы будете использовать его следующим образом:
u := new(User)
if err := u.Get(id); err != nil {
// problem getting user
}
// everything is cool.
Ответ 3
Golang не поддерживает конструкторы.
Вместо этого используйте factory функции (Эффективная ссылка Go). Соглашение заключается в использовании префикса New
:
func NewUser(id int) *User {
// Returns new User instance
}
Разница между конструктором и функцией factory заключается в том, что функция factory не привязана к структуре User
. Это нормальная функция, которая возвращает User
, в то время как конструктор типа Java/С++ - это метод, который изменяет только что созданный объект User
.
Ответ 4
Другой способ вызова имитации статического метода, несмотря на то, что это не так, заключается в следующем:
package main
import "fmt"
type Manager struct {
}
func (m Manager) MyMethod(a float32, b float32) float32 {
return 0.5 * a * b
}
func main() {
fmt.Println((Manager).MyMethod(Manager{}, 15, 25))
}
Но, с моей точки зрения, это менее понятно, чем помещать этот метод в отдельный пакет manager
снаружи от класса Manager