Golang 模式 - 第一部分

2025-06-10

Golang 模式 - 第一部分

大家好!
今天的目标是描述并记录一些 Golang 模式。

正如您从我之前的帖子(go concurrencygo lambdas)中了解到的那样,我最近进入了 Go 领域,并很快发现我从以前的经验中所了解的常见习语并不完全适用于 golang。

嗯,我发现有些模式非常常见,依我拙见,应该作为 Golang 初学者指南的一部分介绍。
示例中的所有代码都在GitHub上。

组常数

标题说明了一切,我们希望将公共常量分组在同一个命名空间中。

// Package constants shows a pattern to group constants together
package constants
// Endpoint contains the endpoint configuration
var Endpoint struct {
Hostname string
Port int
}
func init() {
Endpoint.Hostname = "some-endpoint"
Endpoint.Port = 9090
}
view raw constants.go hosted with ❤ by GitHub
// Package constants shows a pattern to group constants together
package constants
// Endpoint contains the endpoint configuration
var Endpoint struct {
Hostname string
Port int
}
func init() {
Endpoint.Hostname = "some-endpoint"
Endpoint.Port = 9090
}
view raw constants.go hosted with ❤ by GitHub

一个供应商链,一旦其中一个供应商返回非零结果或错误,它就会立即返回。
代码展示了一个示例,其中我们需要从以下可能的来源之一加载配置值:环境变量、配置文件或数据库。
我们希望一旦返回非零结果,就停止搜索配置值。

package chain
import "fmt"
func ExampleChain() {
endpoint, _ := chain(
loadEndpointFromConfigFile,
loadEndpointFromEnvVariables,
loadEndpointFromDatabase,
).get()
fmt.Println(endpoint)
// Output: some-endpoint
}
func loadEndpointFromEnvVariables() (string, error) {
return "", nil
}
func loadEndpointFromConfigFile() (string, error) {
return "", nil
}
func loadEndpointFromDatabase() (string, error) {
return "some-endpoint", nil
}
view raw chain.go hosted with ❤ by GitHub
package chain
import "fmt"
func ExampleChain() {
endpoint, _ := chain(
loadEndpointFromConfigFile,
loadEndpointFromEnvVariables,
loadEndpointFromDatabase,
).get()
fmt.Println(endpoint)
// Output: some-endpoint
}
func loadEndpointFromEnvVariables() (string, error) {
return "", nil
}
func loadEndpointFromConfigFile() (string, error) {
return "", nil
}
func loadEndpointFromDatabase() (string, error) {
return "some-endpoint", nil
}
view raw chain.go hosted with ❤ by GitHub

此处 为链的代码

选项

Options 展示了一种灵活的对象构造方法。
其主要优点是将来可以向对象构造函数添加更多参数,而不会破坏客户端。
在其他语言中,你可能会使用重载构造函数或回退到构建器模式。

Context("Greeting with no Name option", func() {
It("returns default greeting", func() {
greeting := NewGreeting()
Expect(greeting.get()).To(Equal("Hello Stranger"))
})
})
Context("Greeting with Name option", func() {
It("returns custom greeting", func() {
greeting := NewGreeting(Name("Mickey"))
Expect(greeting.get()).To(Equal("Hello Mickey"))
})
})
view raw options_test.go hosted with ❤ by GitHub
Context("Greeting with no Name option", func() {
It("returns default greeting", func() {
greeting := NewGreeting()
Expect(greeting.get()).To(Equal("Hello Stranger"))
})
})
Context("Greeting with Name option", func() {
It("returns custom greeting", func() {
greeting := NewGreeting(Name("Mickey"))
Expect(greeting.get()).To(Equal("Hello Mickey"))
})
})
view raw options_test.go hosted with ❤ by GitHub

此处 为选项的代码

或许

Maybe 是一个可能包含或不包含非空值的容器。

Context("User present", func() {
var greeting string
MaybeUser(getUser(1)).IfPresent(func(u *User) {
greeting = "Hello " + u.name
})
It("greets the user", func() {
Expect(greeting).To(Equal("Hello Mickey"))
})
})
Context("User absent", func() {
var greeting string
MaybeUser(getUser(-1)).WhenAbsent(func() {
greeting = "Hello stranger"
})
It("greets the user", func() {
Expect(greeting).To(Equal("Hello stranger"))
})
})
view raw maybe_test.go hosted with ❤ by GitHub
Context("User present", func() {
var greeting string
MaybeUser(getUser(1)).IfPresent(func(u *User) {
greeting = "Hello " + u.name
})
It("greets the user", func() {
Expect(greeting).To(Equal("Hello Mickey"))
})
})
Context("User absent", func() {
var greeting string
MaybeUser(getUser(-1)).WhenAbsent(func() {
greeting = "Hello stranger"
})
It("greets the user", func() {
Expect(greeting).To(Equal("Hello stranger"))
})
})
view raw maybe_test.go hosted with ❤ by GitHub

函数类型

函数是 Golang 中的“一等公民”。每当我们想要轻松实现策略模式或类似功能时,都可以将其用作类型。
这种模式在 golang http 包中被广泛使用。

package functiontype
import "fmt"
type Greeting func(name string) string
func GreetingService(request Request, greeting Greeting) string {
return fmt.Sprintf("Service says: %s", greeting(request.user))
}
func ExampleFunctionType() {
request := Request{user: "Mickey"}
fmt.Println(
GreetingService(request, func(name string) string {
return fmt.Sprintf("Hola %s!", name)
}),
)
// Output: Service says: Hola Mickey!
}
view raw functiontype.go hosted with ❤ by GitHub
package functiontype
import "fmt"
type Greeting func(name string) string
func GreetingService(request Request, greeting Greeting) string {
return fmt.Sprintf("Service says: %s", greeting(request.user))
}
func ExampleFunctionType() {
request := Request{user: "Mickey"}
fmt.Println(
GreetingService(request, func(name string) string {
return fmt.Sprintf("Hola %s!", name)
}),
)
// Output: Service says: Hola Mickey!
}
view raw functiontype.go hosted with ❤ by GitHub

结论

感谢阅读!

如果您发现它有用,请告诉我,或者是否有一个关键模式确实应该成为此列表的一部分。

鏂囩珷鏉ユ簮锛�https://dev.to/napicella/golang-patterns-5a64
PREV
测试驱动开发示例
NEXT
通过合同测试节省时间