Go 中的有效设计模式
Go 语言实现 10 种设计模式及其在互联网场景中的应用
1. 单例模式(Singleton Pattern)
模式定义(Pattern Definition)
确保只全局创建类的一个实例,并提供统一的访问点。属于创建型模式,适用于需要全局唯一控制的场景。
核心功能(Core Features)
- 唯一实例 :全局只有一个对象实例。
- 自创建 :类本身负责创建实例。
- 全局访问 :通过静态方法或全局变量提供访问。
优点和缺点
优点:
- 确保资源/状态的全局唯一性
- 减少资源的重复创建
- 提供便捷的全球接入点
缺点:
- 违背高内聚原则,模块耦合性高
- 难以隔离单元测试
- 破坏依赖项注入模式
场景应用(Scenario Applications)
- 微服务配置中心:统一管理分布式系统的配置。
- 数据库连接池:控制并发连接数。
- 分布式日志服务:避免重复创建日志处理程序。
- API 请求频率控制:全局共享速率限制状态。
Go 语言实现(并发安全版)
Go
package singleton
import (
"sync"
)
// ConfigManager Singleton struct, simulating configuration management
type ConfigManager struct {
AppConfig map[string]string
}
var (
once sync.Once
instance *ConfigManager
)
// GetInstance 全局访问点,使用 sync.Once 保证并发安全
func GetInstance() *ConfigManager {
once.Do(func() {
instance = &ConfigManager{
AppConfig: map[string]string{
"env": "prod",
"port": "8080",
"timeout": "30s",
},
}
})
return instance
}
// Concurrency test example
func TestConcurrency() {
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
defer wg.Done()
config := GetInstance()
println(config.AppConfig["env"])
}()
}
wg.Wait()
}
2. 工厂模式(Factory Pattern)
模式定义
封装对象创建逻辑,并确定要通过子类实例化的特定产品。它属于创建型模式,并将对象创建与其使用分离。
核心功能
- 封装创建逻辑 :客户端不需要知道具体的创建细节。
- 多态性支持 :通过接口扩展产品系列。
- 开闭原则 : 添加新产品不需要修改现有代码。
优点和缺点
优点
- 将对象创建与使用分开
- 易于扩展新产品
- 遵守依赖关系倒置原则
缺点
- 增加类数(每个产品都需要相应的工厂)
- 工厂类可能会变得过于复杂
- 客户端需要知道产品的抽象接口
应用场景
- 支付网关集成 :根据付款方式创建不同的处理器。
- 云存储客户端 :根据存储服务创建对应的 API 客户端。
- 消息
- 第三方登录服务 :为不同平台动态生成身份验证客户端。
Go语言实现(抽象工厂模式)
go
package factory
import "fmt"
// PaymentProcessor Payment processor interface
type PaymentProcessor interface {
Process(amount float64) string
}
// StripeProcessor Stripe payment implementation
type StripeProcessor struct{}
func (s *StripeProcessor) Process(amount float64) string {
return fmt.Sprintf("Stripe processed $%.2f", amount)
}
// PayPalProcessor PayPal payment implementation
type PayPalProcessor struct{}
func (p *PayPalProcessor) Process(amount float64) string {
return fmt.Sprintf("PayPal processed $%.2f", amount)
}
// PaymentFactory Factory interface
type PaymentFactory interface {
CreateProcessor() PaymentProcessor
}
// StripeFactory Stripe factory implementation
type StripeFactory struct{}
func (s *StripeFactory) CreateProcessor() PaymentProcessor {
return &StripeProcessor{}
}
// PayPalFactory PayPal factory implementation
type PayPalFactory struct{}
func (p *PayPalFactory) CreateProcessor() PaymentProcessor {
return &PayPalProcessor{}
}
// Client usage example
func NewPaymentClient(factory PaymentFactory) PaymentProcessor {
return factory.CreateProcessor()
}
3. 观察者模式(Observer Pattern)
模式定义
定义对象之间的一对多依赖关系,并在主题状态更改时自动通知所有观察者。它属于行为型模式,适用于事件驱动的场景。
核心功能
- 事件驱动 :主题状态的更改会触发观察者的更新。
- 松散耦合 :主体和观察者仅通过抽象接口进行交互。
- 动态订阅 :观察者可以随时注册或取消注册。
优点和缺点
优点
- 支持广播式事件通知
- 易于扩展新的观察者类型
- 遵守开闭原则
缺点
- 大量观察者可能会导致性能问题
- 循环依赖关系可能会导致内存泄漏
- 主体需要维护一个观察者列表
应用场景
- 实时通知系统 :用户订阅主题以接收实时通知。
- 股票报价平台 :投资者认购股票代码以获取价格变动。
- 电子商务库存监控 :用户订阅产品以接收库存变化提醒。
- 分布式系统监控 :监控服务订阅微服务的状态变化。
Go语言实现(事件驱动模型)
go
package observer
import "fmt"
// Observer Observer interface
type Observer interface {
Update(message string)
}
// Subject Subject interface
type Subject interface {
Attach(observer Observer)
Detach(observer Observer)
Notify(message string)
}
// StockTicker Specific subject: stock quotation
type StockTicker struct {
observers []Observer
symbol string
price float64
}
func (s *StockTicker) Attach(observer Observer) {
s.observers = append(s.observers, observer)
}
func (s *StockTicker) Detach(observer Observer) {
for i, o := range s.observers {
if o == observer {
s.observers = append(s.observers[:i], s.observers[i+1:]...)
return
}
}
}
func (s *StockTicker) Notify(message string) {
for _, o := range s.observers {
o.Update(message)
}
}
// Investor Specific observer: investor
type Investor struct {
name string
}
func (i *Investor) Update(message string) {
fmt.Printf("%s received: %s\n", i.name, message)
}
4. 装饰器模式(Decorator Pattern)
模式定义
动态地向对象添加新函数,并通过组合而不是继承来扩展其职责。属于结构型模式,适用于功能分层的场景。
核心功能
- 透明扩展 :保持界面一致,客户端不知道。
- 组合功能 : 支持多层装饰器的嵌套。
- 运行时绑定 :动态确定对象函数的组合。
优点和缺点
优点
- 避免继承层次结构爆炸
- 支持功能自由组合
- 遵守开闭原则
缺点
- 使用多层装饰器进行调试可能很困难
- 过度使用会增加系统的复杂性
- 装饰的顺序可能会影响执行结果
应用场景
- API 中间件 :堆栈日志记录、鉴权、限速等功能。
- 电子商务订单处理 :逐步计算订单总金额。
- 云存储服务 :动态组合存储功能。
- 微服务网关 :请求验证、响应转换和流量监控。
Go语言实现(HTTP 中间件模拟)
go
package decorator
import "fmt"
// Handler Basic processing function
type Handler func(request string) string
// LogDecorator Log decorator
func LogDecorator(next Handler) Handler {
return func(request string) string {
fmt.Printf("Received request: %s\n", request)
return next(request)
}
}
// AuthDecorator Authentication decorator
func AuthDecorator(next Handler) Handler {
return func(request string) string {
if request != "authenticated" {
return "Unauthorized"
}
return next(request)
}
}
// Basic processing function
func BasicHandler(request string) string {
return fmt.Sprintf("Processed: %s", request)
}
// Composite decorator example
func CompositeHandler() Handler {
return LogDecorator(AuthDecorator(BasicHandler))
}
5. 策略模式(Strategy Pattern)
模式定义
将算法封装成独立的策略类,并支持运行时动态切换。它属于行为型模式,适用于多种算法的场景。
核心功能
- 算法封装 :每个策略独立实现算法。
- 策略切换 :在运行时动态选择策略。
- 开闭原则 :添加新策略不需要修改现有代码。
优点和缺点
优点
- 将算法与客户端解耦
- 促进算法扩展和替换
- 支持组合策略
缺点
- 客户需要了解所有策略类型
- 策略类的数量可能会迅速增长
- 策略之间很难共享状态
应用场景
- 电商推广引擎 :根据活动类型动态切换计算逻辑。
- 物流配送系统 :根据用户的选择计算运费。
- 数据排序 :前端请求决定排序策略。
- 广告投放算法:实时调整投放策略。
Go语言实现(电商折扣封装)
go
package strategy
// PromotionStrategy Promotion strategy interface
type PromotionStrategy interface {
Calculate(amount float64) float64
}
// PercentDiscount Percentage discount strategy
type PercentDiscount struct {
rate float64 // Discount rate (0.1 = 10%)
}
func (p *PercentDiscount) Calculate(amount float64) float64 {
return amount * (1 - p.rate)
}
// FixedDiscount Fixed amount discount strategy
type FixedDiscount struct {
offset float64 // Fixed reduction amount
}
func (f *FixedDiscount) Calculate(amount float64) float64 {
if amount > f.offset {
return amount - f.offset
}
return amount
}
// CheckoutContext Checkout context
type CheckoutContext struct {
strategy PromotionStrategy
}
func (c *CheckoutContext) SetStrategy(strategy PromotionStrategy) {
c.strategy = strategy
}
func (c *CheckoutContext) CalculateFinalAmount(amount float64) float64 {
return c.strategy.Calculate(amount)
}
6. 适配器模式(Adapter Pattern)
模式定义
转换不兼容的接口,以便具有不同接口的类可以一起工作。属于结构型模式,适用于系统集成场景。
核心功能
- 接口转换 :使源接口适应目标接口。
- 解耦系统 :客户和被适应者不需要直接交互。
- 兼容性 : 保留原始系统代码并添加适配器层。
优点和缺点
优点
- 解决接口不兼容的问题
- 重用旧系统代码
- 支持双向适配
缺点
- 增加系统抽象层的复杂性
- 过度使用可能会使系统难以维护
- 可能会引入性能开销
应用场景
- 遗留系统迁移(将老系统与微服务架构对接):调整旧的系统 API。
- 第三方库集成(适配 MongoDB 驱动到 SQL 接口):统一数据访问层。
- 跨平台开发(将 iOS/Android 原生 API 适配到统一接口):移动应用程序框架。
- 云服务对接(适配 AWS SQS 为 Kafka 消息格式):混合云架构。
Go语言实现(第三方支付适配)
go
package adapter
import (
"fmt"
)
// ThirdPartyPayment Third-party payment interface (source interface)
type ThirdPartyPayment interface {
ProcessPayment(orderID string, amount float64) error
}
// LegacyPayPal Legacy PayPal implementation (source implementation)
type LegacyPayPal struct{}
func (p *LegacyPayPal) ProcessPayment(orderID string, amount float64) error {
fmt.Printf("Legacy PayPal processing order %s for $%.2f\n", orderID, amount)
return nil
}
// TargetPayment Target payment interface (unified interface)
type TargetPayment interface {
Pay(orderID string, amountUSD float64) error
}
// PayPalAdapter Adapter implementation
type PayPalAdapter struct {
legacy *LegacyPayPal
}
func (a *PayPalAdapter) Pay(orderID string, amountUSD float64) error {
// Convert the target interface to the source interface parameters
return a.legacy.ProcessPayment(orderID, amountUSD)
}
// Example of handling incompatible situations
func HandleIncompatiblePayment(payment ThirdPartyPayment) TargetPayment {
return &PayPalAdapter{legacy: payment.(*LegacyPayPal)}
}
7. 代理模式(Proxy Pattern)
模式定义
为目标对象提供代理层以控制对它的访问。属于结构型模式,适用于远程访问、权限控制等场景。
核心功能
- 访问控制 :代理层拦截和处理请求。
- 懒加载 :按需创建目标对象。
- 职责分离 :代理处理非业务逻辑(日志记录/安全/缓存)。
优点和缺点
优点
- 保护目标对象
- 支持分布式访问
- 实现延迟加载
缺点
- 增加请求处理延迟
- 代理层可能会成为单点故障
- 代理类和目标类的接口需要一致
应用场景
- API 网关 :代理后端微服务并提供统一入口。
- 缓存代理 (Redis/Memcached 缓存层):缓存数据库查询结果。
- 权限代理 (OAuth2 授权服务器):拦截请求并验证用户权限。
- 远程代理(gRPC 远程服务调用):隐藏网络通信的详细信息。
Go语言实现(Cache Proxy)
go
package proxy
import (
"sync"
"time"
)
// RealData Real data object (database query)
type RealData struct {
ID string
Content string
LastUpdate time.Time
}
func (r *RealData) FetchData() string {
// Simulate database query delay
time.Sleep(500 * time.Millisecond)
return r.Content
}
// CacheProxy Cache proxy
type CacheProxy struct {
realData *RealData
cache map[string]string
mu sync.Mutex
}
func NewCacheProxy(id string, content string) *CacheProxy {
return &CacheProxy{
realData: &RealData{ID: id, Content: content, LastUpdate: time.Now()},
cache: make(map[string]string),
}
}
func (c *CacheProxy) FetchData() string {
c.mu.Lock()
defer c.mu.Unlock()
if data, exists := c.cache[c.realData.ID]; exists {
return data // Return the cached data directly
}
// First access, get the real data and cache it
data := c.realData.FetchData()
c.cache[c.realData.ID] = data
return data
}
8. 命令模式(Command Pattern)
模式定义
将请求封装到命令对象中,以实现请求发送方和接收方的解耦。它属于行为型模式,适用于支持撤消和日志记录的场景。
核心功能
- 请求封装 :命令对象包含执行所需的所有信息。
- 事务支持 :支持批量执行和回滚。
- 日志记录 :可以持久保存命令的执行历史。
优点和缺点
优点
- 支持撤消/重做作
- 解耦请求发送和接收
- 支持批处理
缺点
- 命令类的数量可能会显著增加
- 复杂的命令逻辑难以维护
- 需要提前确定命令参数
应用场景
- 版本控制系统(Git 提交作):每个提交都可以被视为支持回滚的命令。
- 数据库事务(ACID作的封装):组合多个 SQL 命令以支持提交/回滚。
- 任务调度系统(任务编排):将分布式任务封装成可执行命令。
- 文本编辑器(撤消/重做功能):将编辑作录制为命令对象。
Go语言实现(Database Transaction Simulation)
go
package command
import (
"database/sql"
"fmt"
)
// DatabaseReceiver Database receiver
type DatabaseReceiver struct {
db *sql.DB
}
func (r *DatabaseReceiver) ExecuteSQL(sqlStmt string) error {
fmt.Printf("Executing: %s\n", sqlStmt)
return nil // Simulate SQL execution
}
func (r *DatabaseReceiver) Rollback() error {
fmt.Println("Rolling back transaction")
return nil // Simulate rollback
}
// Command Command interface
type Command interface {
Execute() error
Undo() error
}
// InsertCommand Insert command
type InsertCommand struct {
receiver *DatabaseReceiver
table string
columns []string
values []string
prevValues map[string]string // Store old values for rollback
}
func (c *InsertCommand) Execute() error {
// Execute the insert logic and record the old values
c.prevValues = getPreviousValues(c.receiver, c.table, c.columns)
return c.receiver.ExecuteSQL(fmt.Sprintf("INSERT INTO %s VALUES (%s)", c.table, c.values))
}
func (c *InsertCommand) Undo() error {
// Use prevValues to roll back the insert operation
return c.receiver.Rollback()
}
9. 组合模式(Composite Pattern)
模式定义
将对象组合成树状结构,并统一处理单个对象(叶)和复合对象(容器)。属于结构型模式,适用于分层管理场景。
核心功能
- 树形结构 :支持部分-整体层次结构。
- 统一接口 :客户端一致地处理叶子和容器。
- 递归处理 :容器对象可以包含其他容器或叶。
优点和缺点
优点
- 简化分层结构作
- 支持复杂的分层遍历
- 遵守开闭原则
缺点
- 更高的设计复杂性
- 叶子和容器的接口需要严格统一
- 功能扩展可能会影响整体结构
应用场景
- 文件系统(云存储桶/对象结构):统一处理文件和文件夹。
- 组织结构(企业 HR 系统中的部门/员工管理):一个部门可以包含子部门和员工。
- 电子商务产品目录(商品的类别/子类别/产品层次结构):分层产品管理。
- GUI 组件(React Native 中的 View/Text 组件嵌套):统一处理 UI 组件树。
Go语言实现(File System Simulation)
go
package composite
import "fmt"
// FileSystemNode File system node interface
type FileSystemNode interface {
List() string
Add(node FileSystemNode)
Remove(node FileSystemNode)
}
// File Leaf node: file
type File struct {
name string
size int
}
func (f *File) List() string {
return fmt.Sprintf("File: %s (%dKB)", f.name, f.size)
}
func (f *File) Add(node FileSystemNode) {}
func (f *File) Remove(node FileSystemNode) {}
// Directory Container node: directory
type Directory struct {
name string
children []FileSystemNode
}
func (d *Directory) List() string {
list := fmt.Sprintf("Directory: %s\n", d.name)
for _, child := range d.children {
list += fmt.Sprintf("├─ %s\n", child.List())
}
return list
}
func (d *Directory) Add(node FileSystemNode) {
d.children = append(d.children, node)
}
func (d *Directory) Remove(node FileSystemNode) {
for i, child := range d.children {
if child == node {
d.children = append(d.children[:i], d.children[i+1:]...)
return
}
}
}
10. 迭代器模式(Iterator Pattern)
模式定义
提供统一的接口来遍历集合的元素并隐藏集合的内部数据结构。它属于行为型模式,适用于数据遍历场景。
核心功能
- 抽象遍历 :客户端不需要知道集合的内部实现。
- 多种遍历模式 :支持正向、反向、过滤等遍历策略。
- 集合解耦 :集合和迭代器可以独立发展。
优点和缺点
优点
- 统一集合访问界面
- 支持复杂数据结构的遍历
- 遵守单一责任原则
缺点
- 增加 iterator 类的设计成本
- 自定义迭代器可能会导致类膨胀
- 迭代器需要维护遍历状态
应用场景
- 大数据处理(遍历 Hadoop MapReduce 中的数据集):统一处理不同的存储格式。
- 数据库 ORM(遍历 GORM 中的结果集):透明地处理不同数据库的返回格式。
- 图形渲染 (Three.js 中场景图节点的遍历):统一处理 3D 对象的层次结构。
- 日志分析(遍历 ELK 中的日志条目):支持遍历不同的日志存储格式。
Go语言实现(自定义集合迭代器)
go
package iterator
import "fmt"
// Collection Collection interface
type Collection interface {
CreateIterator() Iterator
AddItem(item string)
}
// StringCollection String collection implementation
type StringCollection struct {
items []string
}
func (c *StringCollection) CreateIterator() Iterator {
return &StringIterator{collection: c, index: -1}
}
func (c *StringCollection) AddItem(item string) {
c.items = append(c.items, item)
}
// Iterator Iterator interface
type Iterator interface {
Next() bool
Current() string
}
// StringIterator String iterator implementation
type StringIterator struct {
collection *StringCollection
index int
}
func (i *StringIterator) Next() bool {
i.index++
return i.index < len(i.collection.items)
}
func (i *StringIterator) Current() string {
if i.index < len(i.collection.items) {
return i.collection.items[i.index]
}
return ""
}
// Usage example
func TraverseCollection(collection Collection) {
iterator := collection.CreateIterator()
for iterator.Next() {
fmt.Println(iterator.Current())
}
}
总结
Go 语言通过其接口和组合功能为设计模式的实现提供灵活的支持:
- 创建型模式:使用单例模式控制全局状态,使用工厂模式封装对象创建。
- 结构型模式 :通过组合实现装饰器、代理和适配器的功能扩展。
- 行为型模式 :借助接口解耦并实现观察者、策略和命令的交互逻辑。
在实际开发中,应根据具体场景选择合适的模式:
- 对于微服务架构,首选工厂模式和适配器模式。
- 对于事件驱动型系统,建议使用观察者模式和命令模式。
- 对于分层数据管理,组合模式和迭代器模式是首选。
合理使用设计模式可以提高代码的可维护性、可扩展性和可重用性。但是,应避免过度设计,并且应始终将重点放在解决实际问题上。