2013-09-07 29 views
29

Tôi đang tìm kiếm lời khuyên về cách tốt nhất để làm sạch cấu trúc sau. Tôi biết Go không có phương pháp tĩnh và thường là better to encapsulate functionality in a separate package. Các kiểu cấu trúc của tôi tham chiếu lẫn nhau và do đó không thể được khai báo trong các gói riêng biệt do nhập khẩu vòng tròn.Đi: Thiết kế phương pháp "tĩnh"

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 
} 

Nhưng, nếu tôi muốn tải một người dùng hoặc thanh toán, tôi chỉ ném đi người nhận:

var u *User 
user := u.Get(585) 

tôi có thể không gian tên các chức năng bản thân, mà đập vào mắt tôi là ô uế:

func GetUser(id int) *User { 
    // Returns the user with the given id 
} 

func GetPayment(id int) *Payment { 
    // Returns the payment with the given id 
} 

Tôi thực sự muốn có thể gọi .Get hoặc tương tự trên cấu trúc mà không cần viết tên của cấu trúc trong chính hàm đó. Cách thành ngữ để làm điều này là gì?

Trả lời

23

GetUser()GetPayment() tấn công tôi là hoàn toàn rõ ràng và thành ngữ. Tôi không chắc những gì bạn thấy ô uế về chúng.

Gọi .Get() trên cấu trúc để trả về cấu trúc khác là điều khiến tôi rất kỳ quặc, không rõ ràng và không đơn điệu.

Tôi nghĩ đây có thể là trường hợp chỉ gắn bó với thành ngữ và tin tưởng rằng bạn sẽ quen với nó.

+2

Có, tôi tìm thấy '.Get()' trên một cấu trúc mà tôi đang ném đi thậm chí còn ô uế hơn. Với tôi 'User.Get()' là sạch nhất; nếu 'GetUser' là xấp xỉ gần nhất tôi có thể nhận được, tôi sẽ lấy nó. – ash

+1

@ash Có, tôi tin rằng nó là gần nhất bạn có thể nhận được, và cách thành công nhất Go để làm điều đó. –

+0

Bạn không thể tạo các khung công tác và thư viện với GetUser và GetPayment – rocketspacer

10

có chức năng Get hoàn toàn ổn; nó không phải là unidiomatic theo bất kỳ cách nào.

func (u *User) Get(id int) *User không có ý nghĩa gì, tuy nhiên, nó phải là func (u *User) Get(id int) error. Một điều mà bạn đang thiếu là bạn có thể định nghĩa một phương thức nhận trên một con trỏ, và sau đó bên trong của phương thức đó, dereference con trỏ để ghi đè lên những gì nó trỏ đến.

Như thế này:

// 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 
} 

và nếu có bất kỳ vấn đề, trả lại một lỗi. Bây giờ bạn có thể nói

type Getter interface { 
    Get(int) error 
} 

và vì vậy mọi loại định nghĩa Get(id)error đều có thể được xác định. Sau đó, bạn sẽ sử dụng nó như sau:

u := new(User) 
if err := u.Get(id); err != nil { 
    // problem getting user 
} 
// everything is cool. 
11

Golang không hỗ trợ các nhà thầu.

Sử dụng chức năng của nhà máy thay thế (Effective Go reference). Quy ước là sử dụng New tiền tố:

func NewUser(id int) *User { 
    // Returns new User instance 
} 

Sự khác biệt giữa xây dựng và hoạt động nhà máy là chức năng nhà máy không phải là "gắn" vào User struct. Đó là một chức năng bình thường xảy ra để trả về User trong khi hàm tạo Java/C++ giống như một phương thức sửa đổi đối tượng mới được tạo ra User.

Các vấn đề liên quan