🐹 Golang 项目中的常见设计模式 🧩
Golang 被广泛用于构建可扩展且性能良好的系统。由于其简单性和对并发性的强大支持,与其他语言相比,Golang 程序中的一些设计模式更为常见。以下是 Go 中最常用的 **设计模式**:
1. 传统设计模式
1.单例模式
确保整个应用程序中存在类型的单个实例。它通常用于配置文件、日志记录或数据库连接等资源。
**例子:**
package singleton
import "sync"
type Singleton struct{}
var instance *Singleton
var once sync.Once
func GetInstance() *Singleton {
once.Do(func() {
instance = &Singleton{}
})
return instance
}**用途**:记录器、数据库连接或共享配置。
2.工厂模式
提供一种创建对象的方法,无需暴露创建逻辑。它抽象了实例化过程。
**例子:**
package factory
import "fmt"
type Animal interface {
Speak() string
}
type Dog struct{}
func (d Dog) Speak() string { return "Woof!" }
type Cat struct{}
func (c Cat) Speak() string { return "Meow!" }
func AnimalFactory(animalType string) Animal {
switch animalType {
case "dog":
return Dog{}
case "cat":
return Cat{}
default:
return nil
}
}
func main() {
animal := AnimalFactory("dog")
fmt.Println(animal.Speak())
}**用法:**动态创建不同类型的对象。
3.装饰者模式
在运行时动态地向对象添加行为而无需修改其代码。在 Go 中,这是通过函数实现的。
**例子:**
package main
import "fmt"
type Notifier interface {
Send(message string)
}
type EmailNotifier struct{}
func (e EmailNotifier) Send(message string) {
fmt.Println("Email: " + message)
}
func WithSMSNotifier(notifier Notifier) Notifier {
return &struct{ Notifier }{
Notifier: notifier,
}
}
func main() {
email := EmailNotifier{}
email.Send("Hello")
smsNotifier := WithSMSNotifier(email)
smsNotifier.Send("Hello with SMS")
}**用法**:在现有组件周围添加日志、缓存或指标。
4.观察者模式
定义对象之间的一对多依赖关系,以便当一个对象改变状态时,所有依赖者都会收到通知。
**例子:**
package observer
import "fmt"
type Observer interface {
Update(string)
}
type Subject struct {
observers []Observer
}
func (s *Subject) Register(o Observer) {
s.observers = append(s.observers, o)
}
func (s *Subject) Notify(data string) {
for _, observer := range s.observers {
observer.Update(data)
}
}
type EmailClient struct{}
func (e EmailClient) Update(data string) {
fmt.Println("Email received:", data)
}
func main() {
subject := Subject{}
emailClient := EmailClient{}
subject.Register(emailClient)
subject.Notify("New Update Available!")
}**用途**:事件驱动系统或发布-订阅实现。
5.策略模式
定义一组算法,封装每个算法,并使它们可以互换。
**例子:**
package strategy
import "fmt"
type Strategy interface {
Execute(a, b int) int
}
type Add struct{}
func (Add) Execute(a, b int) int { return a + b }
type Multiply struct{}
func (Multiply) Execute(a, b int) int { return a * b }
func main() {
var strategy Strategy = Add{}
fmt.Println("Add:", strategy.Execute(2, 3))
strategy = Multiply{}
fmt.Println("Multiply:", strategy.Execute(2, 3))
}**用法**:在运行时选择算法,例如排序策略。
6.适配器模式
通过提供桥梁使不兼容的接口能够协同工作。
**例子:**
package main
import "fmt"
type OldPrinter interface {
PrintOldMessage() string
}
type LegacyPrinter struct{}
func (lp *LegacyPrinter) PrintOldMessage() string {
return "Legacy Printer: Old message"
}
type NewPrinterAdapter struct {
oldPrinter *LegacyPrinter
}
func (npa *NewPrinterAdapter) PrintMessage() string {
return npa.oldPrinter.PrintOldMessage() + " - adapted"
}
func main() {
adapter := NewPrinterAdapter{&LegacyPrinter{}}
fmt.Println(adapter.PrintMessage())
}**用途**:将遗留代码与新系统集成。
7.建造者模式
逐步简化复杂对象的构建。
**例子:**
package main
import "fmt"
type Car struct {
Wheels int
Color string
}
type CarBuilder struct {
car Car
}
func (cb *CarBuilder) SetWheels(wheels int) *CarBuilder {
cb.car.Wheels = wheels
return cb
}
func (cb *CarBuilder) SetColor(color string) *CarBuilder {
cb.car.Color = color
return cb
}
func (cb *CarBuilder) Build() Car {
return cb.car
}
func main() {
car := CarBuilder{}.
SetWheels(4).
SetColor("Red").
Build()
fmt.Println(car)
}**用法**:构建像配置这样的复杂结构。
8. 责任链模式
沿着处理程序链传递请求。
**例子:**
package main
import "fmt"
type Handler interface {
SetNext(handler Handler)
Handle(request string)
}
type BaseHandler struct {
next Handler
}
func (b *BaseHandler) SetNext(handler Handler) {
b.next = handler
}
func (b *BaseHandler) Handle(request string) {
if b.next != nil {
b.next.Handle(request)
}
}
type ConcreteHandler struct {
BaseHandler
name string
}
func (ch *ConcreteHandler) Handle(request string) {
fmt.Println(ch.name, "handling request:", request)
ch.BaseHandler.Handle(request)
}
func main() {
handler1 := &ConcreteHandler{name: "Handler 1"}
handler2 := &ConcreteHandler{name: "Handler 2"}
handler1.SetNext(handler2)
handler1.Handle("Process this")
}**用途**:HTTP 服务器中的中间件。
9. 命令模式
将请求封装为对象。
**例子:**
package main
import "fmt"
type Command interface {
Execute()
}
type Light struct{}
func (l Light) On() {
fmt.Println("Light is On")
}
type LightOnCommand struct {
light Light
}
func (c LightOnCommand) Execute() {
c.light.On()
}
func main() {
light := Light{}
command := LightOnCommand{light: light}
command.Execute()
}**用法**:任务队列或撤消操作。
10. 期权模式
选项模式提供了一种通过使用功能选项而不是具有许多参数的构造函数来创建灵活、可配置对象的方法。
**例子:**
package main
import "fmt"
// Product represents the product configuration
type Product struct {
Name string
Price float64
}
// Option is a function that modifies the Product configuration
type Option func(*Product)
// NewProduct creates a new Product with optional configurations
func NewProduct(options ...Option) *Product {
p := &Product{} // default product
for _, option := range options {
option(p)
}
return p
}
// WithName sets the product's name
func WithName(name string) Option {
return func(p *Product) {
p.Name = name
}
}
// WithPrice sets the product's price
func WithPrice(price float64) Option {
return func(p *Product) {
p.Price = price
}
}
func main() {
product := NewProduct(WithName("Laptop"), WithPrice(1200.50))
fmt.Println("Product:", *product)
}**用法:**
当您需要为对象提供可选配置时通常使用此模式,允许用户选择要设置的选项。
11. 错误包装器模式
错误包装器模式用于通过添加上下文(例如,附加详细信息或堆栈跟踪)来增强错误,从而使调试更容易。
**例子:**
package main
import (
"fmt"
"errors"
)
// ErrorWrapper wraps an existing error with additional context
type ErrorWrapper struct {
msg string
inner error
}
// Error implements the error interface
func (e *ErrorWrapper) Error() string {
return fmt.Sprintf("%s: %v", e.msg, e.inner)
}
// WrapError creates a new wrapped error
func WrapError(msg string, err error) *ErrorWrapper {
return &ErrorWrapper{
msg: msg,
inner: err,
}
}
func main() {
err := errors.New("database connection failed")
wrappedErr := WrapError("unable to connect to database", err)
fmt.Println(wrappedErr)
}**用法:**
此模式对于为错误添加上下文非常有用,例如包括错误的位置或描述。它在存在多层抽象的复杂系统中尤其有用。
概括:
2.并发模式
在 **Golang** 中,除了传统的设计模式外,开发人员还经常使用 **并发模式** 和其他 Go 特有的惯用模式。这些模式专注于利用 Go 的并发原语,例如 **goroutines**、**channels** 和 **select** 语句,以及构建代码以提高可读性和可维护性。
1. 工作池模式
用于限制执行的并发任务数,提高资源利用率和系统稳定性。
**例子:**
package main
import (
"fmt"
"sync"
"time"
)
func worker(id int, jobs <-chan int, results chan<- int) {
for j := range jobs {
fmt.Printf("Worker %d processing job %d\n", id, j)
time.Sleep(time.Second) // Simulate work
results <- j * 2 // Return result
}
}
func main() {
const numWorkers = 3
const numJobs = 5
jobs := make(chan int, numJobs)
results := make(chan int, numJobs)
// Start worker goroutines
for w := 1; w <= numWorkers; w++ {
go worker(w, jobs, results)
}
// Send jobs to the channel
for j := 1; j <= numJobs; j++ {
jobs <- j
}
close(jobs)
// Collect results
for a := 1; a <= numJobs; a++ {
fmt.Printf("Result: %d\n", <-results)
}
}2. 扇出、扇入模式
**例子:**
package main
import (
"fmt"
"sync"
"time"
)
func producer(ch chan int) {
for i := 1; i <= 5; i++ {
ch <- i
time.Sleep(time.Millisecond * 100)
}
close(ch)
}
func worker(id int, ch <-chan int, results chan<- int, wg *sync.WaitGroup) {
defer wg.Done()
for job := range ch {
fmt.Printf("Worker %d processing %d\n", id, job)
results <- job * 2
}
}
func main() {
jobs := make(chan int, 5)
results := make(chan int, 5)
// Fan-Out: Start workers
var wg sync.WaitGroup
for w := 1; w <= 3; w++ {
wg.Add(1)
go worker(w, jobs, results, &wg)
}
// Fan-In: Collect results
go producer(jobs)
go func() {
wg.Wait()
close(results)
}()
for res := range results {
fmt.Println("Result:", res)
}
}3. 速率限制模式
控制操作速率以防止下游系统超载。
**例子:**
package main
import (
"fmt"
"time"
)
func main() {
rateLimit := time.Tick(500 * time.Millisecond) // Allow 1 task every 500ms
for i := 1; i <= 5; i++ {
<-rateLimit
fmt.Println("Processing task", i, "at", time.Now())
}
}4.管道模式
使用通道将数据传递至一系列处理阶段。
**例子:**
package main
import "fmt"
func generator(nums ...int) <-chan int {
out := make(chan int)
go func() {
for _, n := range nums {
out <- n
}
close(out)
}()
return out
}
func square(in <-chan int) <-chan int {
out := make(chan int)
go func() {
for n := range in {
out <- n * n
}
close(out)
}()
return out
}
func main() {
nums := generator(1, 2, 3, 4)
squares := square(nums)
for n := range squares {
fmt.Println(n)
}
}3. 其他设计模式
5. 存储库模式
抽象数据库层,确保关注点分离和代码清晰。
**例子:**
package repository
type User struct {
ID int
Name string
}
type UserRepository interface {
GetByID(id int) (*User, error)
}
type userRepo struct{}
func (u userRepo) GetByID(id int) (*User, error) {
// DB logic here (e.g., SELECT query)
return &User{ID: id, Name: "Alice"}, nil
}
func NewUserRepository() UserRepository {
return userRepo{}
}6. 发布/订阅模式
实现组件之间的事件驱动的通信模型。
**示例:**使用**通道**进行事件传播:
package main
import "fmt"
func publisher(ch chan<- string) {
ch <- "Event 1"
ch <- "Event 2"
close(ch)
}
func subscriber(ch <-chan string) {
for event := range ch {
fmt.Println("Received:", event)
}
}
func main() {
events := make(chan string)
go publisher(events)
subscriber(events)
}7.配置模式
集中配置管理以实现可维护性和一致性。
**例子:**
package config
import (
"fmt"
"os"
)
type Config struct {
Port string
}
func LoadConfig() Config {
return Config{
Port: os.Getenv("APP_PORT"),
}
}
func main() {
os.Setenv("APP_PORT", "8080")
config := LoadConfig()
fmt.Println("App Port:", config.Port)
}8.断路器模式
通过停止失败的操作来防止分布式系统中的级联故障。
摘要:常见的 Golang 模式
通过结合这些模式,Golang 项目实现了模块化、可扩展性和高效的并发处理——这对于现代分布式系统至关重要。
如果你觉得这篇文章有用,请给我点赞或留言!或者如果你觉得这篇文章可以帮助到别人,请随意分享!非常感谢!😃