问题
Correct me if I'm wrong, but for my understanding of an API is that it is something that allows me to modify and request data through an interface, which is what I want to do in Go. For example I have a user interface:
interface IUser {
GetId() int
GetName() string
GetSignupDate() time
GetPermissions() []IPermission
Delete()
}
This already looks to me like active record and if I want to create a new user with a new id I would have to use new
since Go doesn't support static functions as far as I know. This means I would also need a commit function in my interface, which makes it even worse for me. What am I doing wrong here?
回答1:
In Go, interfaces are behavioural. That is, they describe what a thing does more than what it is. Your example looks like you're trying to write C# in Go, with your heavy use of I in front of interface classes. However, an interface that is only implemented by one type is a bit of a waste of time.
Instead, consider:
interface Deleteable { // You'd probably be tempted to call this IDeleteable
// Effective go suggests Deleter, but the grammar
// sounds weird
Delete() err
}
Now you can create a function to perform batch deletes:
func BatchDelete(victims []Deleteable) {
// Do some cool things for batching, connect to db, start a transaction
for _, victim := range(victims) {
victim.Delete() // Or arrange for this function to be called somehow.
}
}
You'd probably get started faster by creating an interface for Update, Serialize and so on, and storing your actual users/permissions/etc in concrete structs that implement those methods. (Note in Go you don't have to say that a type implements an interface, it happens "automatically"). You also don't have to have a single interface for each method (Updater, Serializable), but you can bundle them all into one interface:
type DBObject interface {
Update()
Serialize() RowType
Delete()
}
type User struct {
Id int
Name string
// ... etc
}
Remember, your model can always "Fill in" a User object to return from your API, even if the actual representation of the User object is something much more diffuse, e.g. RDF triples.
回答2:
I agree with @ZanLynx comments. Go’s standard library seems to favour the interface way for APIs.
package main
import "fmt"
type S string
type I interface{ M() S }
func (s S) M() S { return s }
func API(i I) I { return i.M() }
func main() {
s := S("interface way")
fmt.Println(API(s))
}
It may be worth noting that APIs that take in a one-method interface could be re-written as taking a function type.
package main
import "fmt"
func API(f func() string) string { return f() }
func main() {
f := func() string { return "higher-order way" }
fmt.Println(API(f))
}
As an API author, one could provide both mechanisms and let the API consumer decide the style of invocation. See http://aquaraga.github.io/functional-programming/golang/2016/11/19/golang-interfaces-vs-functions.html.
来源:https://stackoverflow.com/questions/31093981/basic-api-in-golang-antipattern