📚 原创系列: “Go语言学习系列”
🔄 转载说明: 本文最初发布于"Gopher部落"微信公众号,经原作者授权转载。
🔗 关注原创: 欢迎扫描文末二维码,关注"Gopher部落"微信公众号获取第一手Go技术文章。
📑 Go语言学习系列导航
🚀 第四阶段:专业篇本文是【Go语言学习系列】的第50篇,当前位于第四阶段(专业篇)
- 性能优化(一):编写高性能Go代码
- 性能优化(二):profiling深入
- 性能优化(三):并发调优
- 代码质量与最佳实践
- 设计模式在Go中的应用(一)
- 设计模式在Go中的应用(二) 👈 当前位置
- 云原生Go应用开发
- 分布式系统基础
- 高可用系统设计
- 安全编程实践
- Go汇编基础
- 第四阶段项目实战:高性能API网关
📖 文章导读
在本文中,您将了解:
- 行为型设计模式在Go中的实现方式
- 观察者模式、策略模式、命令模式等核心行为模式
- Go的并发特性如何简化行为模式实现
- 如何结合Go的特性优化设计模式实现
- 真实项目中行为模式的应用案例和最佳实践
- 如何避免行为型模式使用中的常见陷阱

设计模式在Go中的应用(二)
在上一篇文章中,我们探讨了创建型和结构型设计模式在Go中的应用。本文将继续这一主题,深入研究行为型设计模式。行为型模式关注对象之间的交互和责任分配,它们帮助我们定义对象之间的通信方式,使系统更加灵活,同时降低对象间的耦合度。
1. 行为型模式基础
行为型模式与创建型模式和结构型模式不同,它专注于对象之间的通信和交互方式。这些模式帮助我们定义良好的交互模式,提高代码的灵活性和可扩展性。
1.1 行为型模式的特点
行为型模式具有以下特点:
- 关注对象和类的交互:定义对象间如何通信和协作。
- 关注职责分配:确保每个对象只负责自己应该处理的任务。
- 减少耦合:通过各种机制减少对象之间的直接依赖。
- 提高灵活性:使系统更容易适应变化。
- 简化通信:为复杂的对象间通信定义清晰的模式。
1.2 Go语言特性与行为型模式
Go语言的一些特性对行为型模式的实现有显著影响:
- 接口和多态:Go的接口机制使得定义对象行为变得简单,而不需要复杂的继承体系。
- 函数类型和闭包:作为一等公民的函数使得某些行为型模式变得更简洁。
- goroutine和channel:Go的并发特性为观察者模式、责任链模式等提供了优雅的实现方式。
- 上下文(context):标准库的context包为超时、取消等行为提供了标准化的解决方案。
// Go的函数类型和接口使行为型模式实现更简洁
type Handler func(data string) (string, error)
// 使用函数链实现处理流程
func Process(data string, handlers ...Handler) (string, error) {
result := data
var err error
for _, handler := range handlers {
result, err = handler(result)
if err != nil {
return "", err
}
}
return result, nil
}
1.3 行为型模式的分类
行为型模式可以分为两大类:
- 类行为型模式:使用继承机制分配行为(在Go中使用组合和接口实现)。
- 对象行为型模式:使用对象组合定义行为。
我们将在本文中讨论以下几种常见的行为型模式:
- 观察者模式(Observer Pattern)
- 策略模式(Strategy Pattern)
- 命令模式(Command Pattern)
- 责任链模式(Chain of Responsibility Pattern)
- 模板方法模式(Template Method Pattern)
- 迭代器模式(Iterator Pattern)
- 状态模式(State Pattern)
- 访问者模式(Visitor Pattern)
- 备忘录模式(Memento Pattern)
- 解释器模式(Interpreter Pattern)
- 中介者模式(Mediator Pattern)
2. 观察者模式(Observer Pattern)
观察者模式是一种行为设计模式,它定义了对象之间的一对多依赖关系,使得当一个对象状态改变时,所有依赖于它的对象都会收到通知并自动更新。
2.1 基本实现
在Go中,观察者模式可以通过接口和切片实现:
// 观察者接口
type Observer interface {
Update(data interface{})
}
// 具体观察者
type ConcreteObserver struct {
id string
}
func NewConcreteObserver(id string) *ConcreteObserver {
return &ConcreteObserver{id: id}
}
func (o *ConcreteObserver) Update(data interface{}) {
fmt.Printf("Observer %s received update with data: %v\n", o.id, data)
}
// 主题接口
type Subject interface {
Register(observer Observer)
Deregister(observer Observer)
NotifyAll(data interface{})
}
// 具体主题
type ConcreteSubject struct {
observers []Observer
mutex sync.Mutex
}
func NewConcreteSubject() *ConcreteSubject {
return &ConcreteSubject{
observers: make([]Observer, 0),
}
}
func (s *ConcreteSubject) Register(observer Observer) {
s.mutex.Lock()
defer s.mutex.Unlock()
s.observers = append(s.observers, observer)
fmt.Println("Observer registered")
}
func (s *ConcreteSubject) Deregister(observer Observer) {
s.mutex.Lock()
defer s.mutex.Unlock()
for i, obs := range s.observers {
if obs == observer {
s.observers = append(s.observers[:i], s.observers[i+1:]...)
fmt.Println("Observer deregistered")
break
}
}
}
func (s *ConcreteSubject) NotifyAll(data interface{}) {
s.mutex.Lock()
observers := make([]Observer, len(s.observers))
copy(observers, s.observers)
s.mutex.Unlock()
for _, observer := range observers {
observer.Update(data)
}
}
// 使用示例
func main() {
subject := NewConcreteSubject()
observer1 := NewConcreteObserver("1")
observer2 := NewConcreteObserver("2")
observer3 := NewConcreteObserver("3")
subject.Register(observer1)
subject.Register(observer2)
subject.Register(observer3)
subject.NotifyAll("Hello Observers!")
subject.Deregister(observer2)
subject.NotifyAll("Observer 2 has left!")
}
2.2 使用通道(Channel)实现观察者模式
利用Go的channel特性,我们可以实现一个事件驱动的观察者模式:
// 定义事件类型
type Event struct {
Type string
Payload interface{}
}
// 事件总线
type EventBus struct {
subscribers map[string][]chan Event
mutex sync.RWMutex
}
func NewEventBus() *EventBus {
return &EventBus{
subscribers: make(map[string][]chan Event),
}
}
// 订阅事件
func (eb *EventBus) Subscribe(eventType string, capacity int) chan Event {
eb.mutex.Lock()
defer eb.mutex.Unlock()
ch := make(chan Event, capacity)
eb.subscribers[eventType] = append(eb.subscribers[eventType], ch)
return ch
}
// 发布事件
func (eb *EventBus) Publish(event Event) {
eb.mutex.RLock()
subscribers, exists := eb.subscribers[event.Type]
eb.mutex.RUnlock()
if !exists {
return
}
for _, subscriber := range subscribers {
// 非阻塞发送事件
select {
case subscriber <- event:
// 成功发送
default:
// 通道已满,丢弃事件
fmt.Printf("Warning: Channel full. Event %s dropped for a subscriber\n", event.Type)
}
}
}
// 使用示例
func main() {
eventBus := NewEventBus()
// 订阅者1订阅"user.created"事件
subscriber1 := eventBus.Subscribe("user.created", 10)
go func() {
for event := range subscriber1 {
fmt.Printf("Subscriber 1 received event: %s with payload: %v\n",
event.Type, event.Payload)
}
}()
// 订阅者2订阅"user.created"和"user.deleted"事件
subscriber2 := eventBus.Subscribe("user.created", 10)
subscriber3 := eventBus.Subscribe("user.deleted", 10)
go func() {
for {
select {
case event := <-subscriber2:
fmt.Printf("Subscriber 2 received event: %s with payload: %v\n",
event.Type, event.Payload)
case event := <-subscriber3:
fmt.Printf("Subscriber 2 received event: %s with payload: %v\n",
event.Type, event.Payload)
}
}
}()
// 发布事件
eventBus.Publish(Event{Type: "user.created", Payload: map[string]string{"id": "1", "name": "John"}})
eventBus.Publish(Event{Type: "user.deleted", Payload: "1"})
// 保持主程序运行一段时间
time.Sleep(1 * time.Second)
}
2.3 观察者模式的应用场景
观察者模式适用于以下场景:
- 事件处理系统:UI交互、用户操作事件、系统状态变更等。
- 消息分发系统:如消息队列、事件总线等。
- 数据同步:当核心数据变更时,通知所有依赖组件更新。
- 分离关注点:将状态变化与响应行为解耦。
在实际开发中,观察者模式有助于提高系统的松耦合性,但也需要注意避免循环通知和管理观察者的性能开销。
3. 策略模式(Strategy Pattern)
策略模式定义了一系列算法,将每个算法封装起来,并使它们可以互换使用。策略模式让算法独立于使用它的客户端而变化。
3.1 基本实现
// 策略接口
type PaymentStrategy interface {
Pay(amount float64) error
}
// 具体策略:信用卡支付
type CreditCardPayment struct {
cardNumber string
cvv string
expiry string
}
func NewCreditCardPayment(cardNumber, cvv, expiry string) *CreditCardPayment {
return &CreditCardPayment{
cardNumber: cardNumber,
cvv: cvv,
expiry: expiry,
}
}
func (p *CreditCardPayment) Pay(amount float64) error {
fmt.Printf("Paying %.2f using Credit Card %s\n", amount, p.cardNumber)
// 实际的信用卡处理逻辑...
return nil
}
// 具体策略:PayPal支付
type PayPalPayment struct {
email string
password string
}
func NewPayPalPayment(email, password string) *PayPalPayment {
return &PayPalPayment{
email: email,
password: password,
}
}
func (p *PayPalPayment) Pay(amount float64) error {
fmt.Printf("Paying %.2f using PayPal account %s\n", amount, p.email)
// 实际的PayPal处理逻辑...
return nil
}
// 具体策略:银行转账
type BankTransferPayment struct {
accountNumber string
bankCode string
}
func NewBankTransferPayment(accountNumber, bankCode string) *BankTransferPayment {
return &BankTransferPayment{
accountNumber: accountNumber,
bankCode: bankCode,
}
}
func (p *BankTransferPayment) Pay(amount float64) error {
fmt.Printf("Paying %.2f using Bank Transfer from account %s\n", amount, p.accountNumber)
// 实际的银行转账处理逻辑...
return nil
}
// 上下文:使用选定的支付策略
type PaymentContext struct {
strategy PaymentStrategy
}
func NewPaymentContext(strategy PaymentStrategy) *PaymentContext {
return &PaymentContext{
strategy: strategy,
}
}
func (pc *PaymentContext) SetStrategy(strategy PaymentStrategy) {
pc.strategy = strategy
}
func (pc *PaymentContext) ExecutePayment(amount float64) error {
return pc.strategy.Pay(amount)
}
// 使用示例
func main() {
creditCardPayment := NewCreditCardPayment("1234-5678-9012-3456", "123", "12/25")
paypalPayment := NewPayPalPayment("user@example.com", "password")
bankTransferPayment := NewBankTransferPayment("12345678", "ABCDEF")
// 创建支付上下文,默认使用信用卡支付
paymentContext := NewPaymentContext(creditCardPayment)
// 执行支付
paymentContext.ExecutePayment(100.50)
// 更改策略为PayPal支付
paymentContext.SetStrategy(paypalPayment)
paymentContext.ExecutePayment(50.75)
// 更改策略为银行转账
paymentContext.SetStrategy(bankTransferPayment)
paymentContext.ExecutePayment(1500.00)
}
3.2 使用函数实现策略模式
Go语言支持函数作为一等公民,可以使用函数类型实现更简洁的策略模式:
// 使用函数类型定义策略
type PaymentStrategyFunc func(amount float64) error
// 支付上下文
type PaymentContext struct {
strategy PaymentStrategyFunc
}
func NewPaymentContext(strategy PaymentStrategyFunc) *PaymentContext {
return &PaymentContext{
strategy: strategy,
}
}
func (pc *PaymentContext) SetStrategy(strategy PaymentStrategyFunc) {
pc.strategy = strategy
}
func (pc *PaymentContext) ExecutePayment(amount float64) error {
return pc.strategy(amount)
}
// 定义各种支付策略函数
func CreditCardPayment(cardNumber, cvv, expiry string) PaymentStrategyFunc {
return func(amount float64) error {
fmt.Printf("Paying %.2f using Credit Card %s\n", amount, cardNumber)
// 实际的信用卡处理逻辑...
return nil
}
}
func PayPalPayment(email, password string) PaymentStrategyFunc {
return func(amount float64) error {
fmt.Printf("Paying %.2f using PayPal account %s\n", amount, email)
// 实际的PayPal处理逻辑...
return nil
}
}
func BankTransferPayment(accountNumber, bankCode string) PaymentStrategyFunc {
return func(amount float64) error {
fmt.Printf("Paying %.2f using Bank Transfer from account %s\n", amount, accountNumber)
// 实际的银行转账处理逻辑...
return nil
}
}
// 使用示例
func main() {
// 创建各种支付策略
creditCard := CreditCardPayment("1234-5678-9012-3456", "123", "12/25")
paypal := PayPalPayment("user@example.com", "password")
bankTransfer := BankTransferPayment("12345678", "ABCDEF")
// 使用信用卡策略
paymentContext := NewPaymentContext(creditCard)
paymentContext.ExecutePayment(100.50)
// 切换到PayPal
paymentContext.SetStrategy(paypal)
paymentContext.ExecutePayment(50.75)
// 切换到银行转账
paymentContext.SetStrategy(bankTransfer)
paymentContext.ExecutePayment(1500.00)
}
3.3 策略模式的应用场景
策略模式适用于以下场景:
- 算法可互换:需要在运行时选择不同算法的场景。
- 条件语句复杂:当有复杂的条件语句决定使用不同算法时。
- 算法独立于客户端:隐藏算法复杂性,客户端只需知道如何使用。
- 多种相关类仅在行为上不同:如不同的排序算法、验证策略、支付方式等。
策略模式是Go项目中常用的模式之一,特别适合与函数式编程风格结合使用。
4. 命令模式(Command Pattern)
命令模式将请求封装为一个对象,从而使你可以用不同的请求对客户端进行参数化,对请求排队或记录请求日志,以及支持可撤销的操作。
4.1 基本实现
// 命令接口
type Command interface {
Execute() error
Undo() error
}
// 接收者:文本编辑器
type TextEditor struct {
text string
}
func (e *TextEditor) InsertText(text string) {
e.text += text
fmt.Printf("Text inserted: %s\n", text)
}
func (e *TextEditor) DeleteText(length int) string {
if length <= 0 || len(e.text) == 0 {
return ""
}
startPos := len(e.text) - length
if startPos < 0 {
startPos = 0
length = len(e.text)
}
deletedText := e.text[startPos:]
e.text = e.text[:startPos]
fmt.Printf("Text deleted: %s\n", deletedText)
return deletedText
}
func (e *TextEditor) GetText() string {
return e.text
}
// 具体命令:插入文本
type InsertTextCommand struct {
editor *TextEditor
text string
}
func NewInsertTextCommand(editor *TextEditor, text string) *InsertTextCommand {
return &InsertTextCommand{
editor: editor,
text: text,
}
}
func (c *InsertTextCommand) Execute() error {
c.editor.InsertText(c.text)
return nil
}
func (c *InsertTextCommand) Undo() error {
c.editor.DeleteText(len(c.text))
return nil
}
// 具体命令:删除文本
type DeleteTextCommand struct {
editor *TextEditor
length int
deletedText string
}
func NewDeleteTextCommand(editor *TextEditor, length int) *DeleteTextCommand {
return &DeleteTextCommand{
editor: editor,
length: length,
}
}
func (c *DeleteTextCommand) Execute() error {
c.deletedText = c.editor.DeleteText(c.length)
return nil
}
func (c *DeleteTextCommand) Undo() error {
c.editor.InsertText(c.deletedText)
return nil
}
// 调用者:命令历史
type CommandHistory struct {
commands []Command
position int // 当前命令位置
}
func NewCommandHistory() *CommandHistory {
return &CommandHistory{
commands: make([]Command, 0),
position: -1,
}
}
func (h *CommandHistory) ExecuteCommand(command Command) error {
// 如果我们在历史中间执行新命令,则丢弃后面的命令
if h.position < len(h.commands)-1 {
h.commands = h.commands[:h.position+1]
}
// 执行命令
if err := command.Execute(); err != nil {
return err
}
// 添加到历史
h.commands = append(h.commands, command)
h.position++
return nil
}
func (h *CommandHistory) Undo() error {
if h.position < 0 {
return errors.New("nothing to undo")
}
command := h.commands[h.position]
if err := command.Undo(); err != nil {
return err
}
h.position--
return nil
}
func (h *CommandHistory) Redo() error {
if h.position >= len(h.commands)-1 {
return errors.New("nothing to redo")
}
h.position++
command := h.commands[h.position]
return command.Execute()
}
// 使用示例
func main() {
editor := &TextEditor{}
history := NewCommandHistory()
// 执行命令
history.ExecuteCommand(NewInsertTextCommand(editor, "Hello, "))
history.ExecuteCommand(NewInsertTextCommand(editor, "World!"))
fmt.Printf("Current text: %s\n", editor.GetText()) // Hello, World!
// 撤销上一个命令
history.Undo()
fmt.Printf("After undo: %s\n", editor.GetText()) // Hello,
// 撤销另一个命令
history.Undo()
fmt.Printf("After another undo: %s\n", editor.GetText()) // 空
// 重做命令
history.Redo()
fmt.Printf("After redo: %s\n", editor.GetText()) // Hello,
// 执行新命令
history.ExecuteCommand(NewInsertTextCommand(editor, "Go!"))
fmt.Printf("Final text: %s\n", editor.GetText()) // Hello, Go!
}
4.2 函数式命令模式
利用Go的函数类型,我们可以实现更简洁的命令模式:
// 命令函数类型
type ExecuteFunc func() error
type UndoFunc func() error
// 命令
type FuncCommand struct {
executeFunc ExecuteFunc
undoFunc UndoFunc
}
func NewFuncCommand(executeFunc ExecuteFunc, undoFunc UndoFunc) *FuncCommand {
return &FuncCommand{
executeFunc: executeFunc,
undoFunc: undoFunc,
}
}
func (c *FuncCommand) Execute() error {
return c.executeFunc()
}
func (c *FuncCommand) Undo() error {
return c.undoFunc()
}
// 命令管理器
type CommandManager struct {
commands []Command
position int
}
func NewCommandManager() *CommandManager {
return &CommandManager{
commands: make([]Command, 0),
position: -1,
}
}
func (m *CommandManager) Execute(command Command) error {
if m.position < len(m.commands)-1 {
m.commands = m.commands[:m.position+1]
}
if err := command.Execute(); err != nil {
return err
}
m.commands = append(m.commands, command)
m.position++
return nil
}
func (m *CommandManager) Undo() error {
if m.position < 0 {
return errors.New("nothing to undo")
}
command := m.commands[m.position]
if err := command.Undo(); err != nil {
return err
}
m.position--
return nil
}
func (m *CommandManager) Redo() error {
if m.position >= len(m.commands)-1 {
return errors.New("nothing to redo")
}
m.position++
command := m.commands[m.position]
return command.Execute()
}
// 使用示例
func main() {
// 应用状态
counter := 0
// 命令管理器
manager := NewCommandManager()
// 创建递增命令
incrementCommand := NewFuncCommand(
func() error {
counter++
fmt.Printf("Counter incremented to: %d\n", counter)
return nil
},
func() error {
counter--
fmt.Printf("Counter decremented to: %d\n", counter)
return nil
},
)
// 创建递减命令
decrementCommand := NewFuncCommand(
func() error {
counter--
fmt.Printf("Counter decremented to: %d\n", counter)
return nil
},
func() error {
counter++
fmt.Printf("Counter incremented to: %d\n", counter)
return nil
},
)
// 执行命令
manager.Execute(incrementCommand) // 1
manager.Execute(incrementCommand) // 2
manager.Execute(decrementCommand) // 1
// 撤销和重做
manager.Undo() // 2
manager.Undo() // 1
manager.Redo() // 2
fmt.Printf("Final counter value: %d\n", counter)
}
4.3 命令模式的应用场景
命令模式适用于以下场景:
- 需要支持撤销/重做操作:如文本编辑器、图形编辑软件。
- 需要将请求排队或延迟执行:如作业调度、任务队列。
- 需要支持事务操作:所有命令要么全部执行成功,要么全部回滚。
- 需要记录操作历史:日志记录、操作审计。
- 需要支持回调功能:在事件发生时执行特定操作。
5. 责任链模式(Chain of Responsibility Pattern)
责任链模式为请求创建了一个处理对象的链。请求沿着链传递直到被处理或到达链的末端。
5.1 基本实现
// 处理器接口
type Handler interface {
SetNext(handler Handler) Handler
Handle(request string) (string, error)
}
// 基础处理器
type AbstractHandler struct {
nextHandler Handler
}
func (h *AbstractHandler) SetNext(handler Handler) Handler {
h.nextHandler = handler
return handler
}
func (h *AbstractHandler) Handle(request string) (string, error) {
if h.nextHandler != nil {
return h.nextHandler.Handle(request)
}
return "", errors.New("no handler found for the request")
}
// 具体处理器:身份验证
type AuthenticationHandler struct {
AbstractHandler
}
func (h *AuthenticationHandler) Handle(request string) (string, error) {
if strings.HasPrefix(request, "Auth:") {
// 处理身份验证请求
return fmt.Sprintf("Authentication processed: %s", request), nil
}
// 传递给下一个处理器
return h.AbstractHandler.Handle(request)
}
// 具体处理器:授权
type AuthorizationHandler struct {
AbstractHandler
}
func (h *AuthorizationHandler) Handle(request string) (string, error) {
if strings.HasPrefix(request, "Authorize:") {
// 处理授权请求
return fmt.Sprintf("Authorization processed: %s", request), nil
}
// 传递给下一个处理器
return h.AbstractHandler.Handle(request)
}
// 具体处理器:数据验证
type ValidationHandler struct {
AbstractHandler
}
func (h *ValidationHandler) Handle(request string) (string, error) {
if strings.HasPrefix(request, "Validate:") {
// 处理数据验证请求
return fmt.Sprintf("Validation processed: %s", request), nil
}
// 传递给下一个处理器
return h.AbstractHandler.Handle(request)
}
// 使用示例
func main() {
// 创建处理器链
authHandler := &AuthenticationHandler{}
authzHandler := &AuthorizationHandler{}
validationHandler := &ValidationHandler{}
// 构建责任链
authHandler.SetNext(authzHandler).SetNext(validationHandler)
// 处理不同类型的请求
requests := []string{
"Auth: Login user",
"Authorize: Access resource X",
"Validate: Form data",
"Unknown: Request",
}
for _, request := range requests {
result, err := authHandler.Handle(request)
if err != nil {
fmt.Printf("Error: %v\n", err)
} else {
fmt.Println(result)
}
}
}
5.2 使用函数实现责任链
利用Go的函数类型,我们可以实现更灵活的责任链模式:
// 处理器函数类型
type HandlerFunc func(request string) (string, bool)
// 责任链
type RequestChain struct {
handlers []HandlerFunc
}
func NewRequestChain() *RequestChain {
return &RequestChain{
handlers: make([]HandlerFunc, 0),
}
}
func (c *RequestChain) AddHandler(handler HandlerFunc) *RequestChain {
c.handlers = append(c.handlers, handler)
return c
}
func (c *RequestChain) Process(request string) (string, error) {
for _, handler := range c.handlers {
result, handled := handler(request)
if handled {
return result, nil
}
}
return "", errors.New("no handler found for the request")
}
// 使用示例
func main() {
// 创建责任链
chain := NewRequestChain()
// 添加处理器
chain.AddHandler(func(request string) (string, bool) {
if strings.HasPrefix(request, "Auth:") {
return fmt.Sprintf("Authentication processed: %s", request), true
}
return "", false
}).AddHandler(func(request string) (string, bool) {
if strings.HasPrefix(request, "Authorize:") {
return fmt.Sprintf("Authorization processed: %s", request), true
}
return "", false
}).AddHandler(func(request string) (string, bool) {
if strings.HasPrefix(request, "Validate:") {
return fmt.Sprintf("Validation processed: %s", request), true
}
return "", false
})
// 处理请求
requests := []string{
"Auth: Login user",
"Authorize: Access resource X",
"Validate: Form data",
"Unknown: Request",
}
for _, request := range requests {
result, err := chain.Process(request)
if err != nil {
fmt.Printf("Error: %v\n", err)
} else {
fmt.Println(result)
}
}
}
5.3 中间件作为责任链
在Web开发中,责任链模式经常通过中间件实现:
// HTTP处理器类型
type HandlerFunc func(w http.ResponseWriter, r *http.Request) error
// 中间件类型
type MiddlewareFunc func(HandlerFunc) HandlerFunc
// 责任链应用
func ApplyMiddleware(h HandlerFunc, middleware ...MiddlewareFunc) http.HandlerFunc {
for i := len(middleware) - 1; i >= 0; i-- {
h = middleware[i](h)
}
return func(w http.ResponseWriter, r *http.Request) {
err := h(w, r)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}
}
// 日志中间件
func LoggingMiddleware(next HandlerFunc) HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) error {
start := time.Now()
fmt.Printf("Started %s %s\n", r.Method, r.URL.Path)
err := next(w, r)
fmt.Printf("Completed in %v\n", time.Since(start))
return err
}
}
// 认证中间件
func AuthMiddleware(next HandlerFunc) HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) error {
token := r.Header.Get("Authorization")
if token == "" {
return errors.New("unauthorized: no token provided")
}
// 验证token...
return next(w, r)
}
}
// 使用示例
func main() {
// 处理函数
handleGetUser := func(w http.ResponseWriter, r *http.Request) error {
// 获取用户逻辑...
fmt.Fprintf(w, "User details")
return nil
}
// 应用中间件
handler := ApplyMiddleware(
handleGetUser,
LoggingMiddleware,
AuthMiddleware,
)
http.HandleFunc("/user", handler)
http.ListenAndServe(":8080", nil)
}
5.4 责任链模式的应用场景
责任链模式适用于以下场景:
- 多个对象可能处理请求:需要根据运行时状态确定处理器。
- 处理顺序不确定:需要灵活安排处理顺序。
- 请求处理和请求发送解耦:发送者不需要知道谁会处理请求。
- 职责动态添加:希望在运行时动态添加或移除处理器。
在Go中,责任链模式在Web框架的中间件、过滤器、拦截器等场景中应用广泛。
6. 模板方法模式(Template Method Pattern)
模板方法模式定义了一个算法的骨架,并允许子类为一个或多个步骤提供实现。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法的某些步骤。
6.1 基本实现
在Go中,由于没有传统的继承机制,模板方法模式通常通过接口和组合实现:
// 数据处理器接口
type DataProcessor interface {
Process() error
ReadData() ([]byte, error)
ParseData(data []byte) (interface{}, error)
TransformData(data interface{}) (interface{}, error)
SaveData(data interface{}) error
}
// 基础处理器实现模板方法
type BaseDataProcessor struct {
processor DataProcessor
}
func NewBaseDataProcessor(processor DataProcessor) *BaseDataProcessor {
return &BaseDataProcessor{processor: processor}
}
// 定义算法骨架
func (p *BaseDataProcessor) Process() error {
// 步骤1: 读取数据
data, err := p.processor.ReadData()
if err != nil {
return err
}
// 步骤2: 解析数据
parsedData, err := p.processor.ParseData(data)
if err != nil {
return err
}
// 步骤3: 转换数据
transformedData, err := p.processor.TransformData(parsedData)
if err != nil {
return err
}
// 步骤4: 保存数据
return p.processor.SaveData(transformedData)
}
// CSV数据处理器
type CSVProcessor struct {
*BaseDataProcessor
filePath string
outputPath string
}
func NewCSVProcessor(filePath, outputPath string) *CSVProcessor {
processor := &CSVProcessor{
filePath: filePath,
outputPath: outputPath,
}
processor.BaseDataProcessor = NewBaseDataProcessor(processor)
return processor
}
func (p *CSVProcessor) ReadData() ([]byte, error) {
fmt.Printf("Reading CSV data from %s\n", p.filePath)
// 实际读取逻辑...
return []byte("sample,csv,data"), nil
}
func (p *CSVProcessor) ParseData(data []byte) (interface{}, error) {
fmt.Println("Parsing CSV data")
// 实际解析CSV逻辑...
return strings.Split(string(data), ","), nil
}
func (p *CSVProcessor) TransformData(data interface{}) (interface{}, error) {
fmt.Println("Transforming CSV data")
rows := data.([]string)
// 实际转换逻辑,例如大写转换
for i, row := range rows {
rows[i] = strings.ToUpper(row)
}
return rows, nil
}
func (p *CSVProcessor) SaveData(data interface{}) error {
fmt.Printf("Saving processed data to %s\n", p.outputPath)
// 实际保存逻辑...
rows := data.([]string)
fmt.Printf("Transformed data: %v\n", rows)
return nil
}
// JSON数据处理器
type JSONProcessor struct {
*BaseDataProcessor
filePath string
outputPath string
}
func NewJSONProcessor(filePath, outputPath string) *JSONProcessor {
processor := &JSONProcessor{
filePath: filePath,
outputPath: outputPath,
}
processor.BaseDataProcessor = NewBaseDataProcessor(processor)
return processor
}
func (p *JSONProcessor) ReadData() ([]byte, error) {
fmt.Printf("Reading JSON data from %s\n", p.filePath)
// 实际读取逻辑...
return []byte(`{"name":"sample","values":[1,2,3]}`), nil
}
func (p *JSONProcessor) ParseData(data []byte) (interface{}, error) {
fmt.Println("Parsing JSON data")
// 实际解析JSON逻辑...
var result map[string]interface{}
err := json.Unmarshal(data, &result)
return result, err
}
func (p *JSONProcessor) TransformData(data interface{}) (interface{}, error) {
fmt.Println("Transforming JSON data")
jsonData := data.(map[string]interface{})
// 实际转换逻辑...
jsonData["processed"] = true
jsonData["timestamp"] = time.Now().Unix()
return jsonData, nil
}
func (p *JSONProcessor) SaveData(data interface{}) error {
fmt.Printf("Saving processed JSON to %s\n", p.outputPath)
// 实际保存逻辑...
jsonData := data.(map[string]interface{})
result, _ := json.MarshalIndent(jsonData, "", " ")
fmt.Printf("Transformed data: %s\n", result)
return nil
}
// 使用示例
func main() {
// 处理CSV
csvProcessor := NewCSVProcessor("data.csv", "processed.csv")
csvProcessor.Process()
fmt.Println("----------------------")
// 处理JSON
jsonProcessor := NewJSONProcessor("data.json", "processed.json")
jsonProcessor.Process()
}
6.2 通过闭包实现模板方法
在Go中,我们也可以通过闭包和函数式编程实现模板方法模式:
// 定义处理步骤函数类型
type ReadDataFunc func() ([]byte, error)
type ParseDataFunc func([]byte) (interface{}, error)
type TransformDataFunc func(interface{}) (interface{}, error)
type SaveDataFunc func(interface{}) error
// 数据处理器
type FuncDataProcessor struct {
readData ReadDataFunc
parseData ParseDataFunc
transformData TransformDataFunc
saveData SaveDataFunc
}
// 创建处理器
func NewFuncDataProcessor(
readData ReadDataFunc,
parseData ParseDataFunc,
transformData TransformDataFunc,
saveData SaveDataFunc,
) *FuncDataProcessor {
return &FuncDataProcessor{
readData: readData,
parseData: parseData,
transformData: transformData,
saveData: saveData,
}
}
// 处理函数 - 模板方法
func (p *FuncDataProcessor) Process() error {
// 步骤1: 读取数据
data, err := p.readData()
if err != nil {
return err
}
// 步骤2: 解析数据
parsedData, err := p.parseData(data)
if err != nil {
return err
}
// 步骤3: 转换数据
transformedData, err := p.transformData(parsedData)
if err != nil {
return err
}
// 步骤4: 保存数据
return p.saveData(transformedData)
}
// 创建CSV处理器工厂
func CreateCSVProcessor(filePath, outputPath string) *FuncDataProcessor {
return NewFuncDataProcessor(
// 读取数据
func() ([]byte, error) {
fmt.Printf("Reading CSV data from %s\n", filePath)
return []byte("sample,csv,data"), nil
},
// 解析数据
func(data []byte) (interface{}, error) {
fmt.Println("Parsing CSV data")
return strings.Split(string(data), ","), nil
},
// 转换数据
func(data interface{}) (interface{}, error) {
fmt.Println("Transforming CSV data")
rows := data.([]string)
for i, row := range rows {
rows[i] = strings.ToUpper(row)
}
return rows, nil
},
// 保存数据
func(data interface{}) error {
fmt.Printf("Saving processed data to %s\n", outputPath)
rows := data.([]string)
fmt.Printf("Transformed data: %v\n", rows)
return nil
},
)
}
// 创建JSON处理器工厂
func CreateJSONProcessor(filePath, outputPath string) *FuncDataProcessor {
return NewFuncDataProcessor(
// 读取数据
func() ([]byte, error) {
fmt.Printf("Reading JSON data from %s\n", filePath)
return []byte(`{"name":"sample","values":[1,2,3]}`), nil
},
// 解析数据
func(data []byte) (interface{}, error) {
fmt.Println("Parsing JSON data")
var result map[string]interface{}
err := json.Unmarshal(data, &result)
return result, err
},
// 转换数据
func(data interface{}) (interface{}, error) {
fmt.Println("Transforming JSON data")
jsonData := data.(map[string]interface{})
jsonData["processed"] = true
jsonData["timestamp"] = time.Now().Unix()
return jsonData, nil
},
// 保存数据
func(data interface{}) error {
fmt.Printf("Saving processed JSON to %s\n", outputPath)
jsonData := data.(map[string]interface{})
result, _ := json.MarshalIndent(jsonData, "", " ")
fmt.Printf("Transformed data: %s\n", result)
return nil
},
)
}
// 使用示例
func main() {
// 处理CSV
csvProcessor := CreateCSVProcessor("data.csv", "processed.csv")
csvProcessor.Process()
fmt.Println("----------------------")
// 处理JSON
jsonProcessor := CreateJSONProcessor("data.json", "processed.json")
jsonProcessor.Process()
}
6.3 模板方法模式的应用场景
模板方法模式适用于以下场景:
- 算法结构固定:算法的步骤是固定的,但步骤的实现可能因对象而异。
- 公共代码重用:将算法的通用部分放在模板方法中,避免重复代码。
- 控制子步骤:允许父类控制算法结构,而子类提供具体实现。
- 扩展点封装:封装可变的部分,公开稳定的部分。
Go中的模板方法模式特别适合数据处理、文件处理、批处理等场景,可以结合接口和函数式编程灵活实现。
7. 迭代器模式(Iterator Pattern)
迭代器模式提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露该对象的内部表示。
7.1 基本实现
Go语言有内置的迭代器模式支持,通过range关键字可以迭代数组、切片、映射和通道。但在某些场景下,我们需要自定义迭代器:
// 迭代器接口
type Iterator interface {
HasNext() bool
Next() interface{}
}
// 可迭代集合接口
type Iterable interface {
Iterator() Iterator
}
// 书籍结构
type Book struct {
Title string
Author string
ISBN string
}
// 书籍集合
type BookCollection struct {
books []*Book
}
func NewBookCollection() *BookCollection {
return &BookCollection{
books: make([]*Book, 0),
}
}
func (c *BookCollection) AddBook(book *Book) {
c.books = append(c.books, book)
}
func (c *BookCollection) Iterator() Iterator {
return &BookIterator{
books: c.books,
position: 0,
}
}
// 书籍迭代器
type BookIterator struct {
books []*Book
position int
}
func (i *BookIterator) HasNext() bool {
return i.position < len(i.books)
}
func (i *BookIterator) Next() interface{} {
if !i.HasNext() {
return nil
}
book := i.books[i.position]
i.position++
return book
}
// 使用示例
func main() {
// 创建书籍集合
collection := NewBookCollection()
collection.AddBook(&Book{"Go编程语言", "Alan A. A. Donovan", "978-0134190440"})
collection.AddBook(&Book{"Go Web编程", "Sau Sheong Chang", "978-1617292569"})
collection.AddBook(&Book{"Go语言实战", "William Kennedy", "978-1617291784"})
// 获取迭代器
iterator := collection.Iterator()
// 迭代集合
for iterator.HasNext() {
book := iterator.Next().(*Book)
fmt.Printf("Book: %s by %s (ISBN: %s)\n", book.Title, book.Author, book.ISBN)
}
}
7.2 通道作为迭代器
利用Go的通道特性,我们可以实现更具Go特色的迭代器模式:
// 定义生成器函数
type Generator func(done <-chan struct{}) <-chan interface{}
// 书籍过滤器
type Filter func(book *Book) bool
// 返回书籍生成器
func BookGenerator(books []*Book, done <-chan struct{}) <-chan *Book {
bookChan := make(chan *Book)
go func() {
defer close(bookChan)
for _, book := range books {
select {
case bookChan <- book:
// 书籍成功发送
case <-done:
// 操作被取消
return
}
}
}()
return bookChan
}
// 过滤书籍
func FilterBooks(done <-chan struct{}, bookChan <-chan *Book, filter Filter) <-chan *Book {
filteredChan := make(chan *Book)
go func() {
defer close(filteredChan)
for book := range bookChan {
if filter(book) {
select {
case filteredChan <- book:
// 书籍成功发送
case <-done:
// 操作被取消
return
}
}
}
}()
return filteredChan
}
// 使用示例
func main() {
// 书籍集合
books := []*Book{
{"Go编程语言", "Alan A. A. Donovan", "978-0134190440"},
{"Java编程思想", "Bruce Eckel", "978-0131872486"},
{"Go Web编程", "Sau Sheong Chang", "978-1617292569"},
{"Python编程", "Mark Lutz", "978-1449355739"},
{"Go语言实战", "William Kennedy", "978-1617291784"},
}
// 创建取消通道
done := make(chan struct{})
defer close(done)
// 创建书籍生成器
bookChan := BookGenerator(books, done)
// 过滤Go相关书籍
goBookFilter := func(book *Book) bool {
return strings.Contains(book.Title, "Go")
}
goBooks := FilterBooks(done, bookChan, goBookFilter)
// 迭代过滤后的书籍
for book := range goBooks {
fmt.Printf("Go Book: %s by %s (ISBN: %s)\n", book.Title, book.Author, book.ISBN)
}
}
7.3 迭代器模式的应用场景
迭代器模式适用于以下场景:
- 访问集合内容而不暴露内部结构:客户端只需要知道如何迭代。
- 提供统一的遍历接口:支持不同集合类型的统一访问方式。
- 支持多种遍历方式:不同迭代器可以实现不同的遍历算法。
- 并行迭代:在Go中,可以利用通道实现并行迭代。
在Go中,虽然内置的range关键字已经提供了基本的迭代功能,但在复杂数据结构或需要特殊遍历逻辑时,自定义迭代器仍然非常有用。
8. 状态模式(State Pattern)
状态模式允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。
8.1 基本实现
// 状态接口
type State interface {
Handle(context *Context) string
}
// 上下文类
type Context struct {
state State
}
func NewContext(initialState State) *Context {
return &Context{state: initialState}
}
func (c *Context) SetState(state State) {
c.state = state
}
func (c *Context) Request() string {
return c.state.Handle(c)
}
// 开始状态
type StartState struct{}
func (s *StartState) Handle(context *Context) string {
context.SetState(&RunningState{})
return "Starting the process"
}
// 运行状态
type RunningState struct{}
func (s *RunningState) Handle(context *Context) string {
context.SetState(&PausedState{})
return "Process is running"
}
// 暂停状态
type PausedState struct{}
func (s *PausedState) Handle(context *Context) string {
context.SetState(&StoppedState{})
return "Process is paused"
}
// 停止状态
type StoppedState struct{}
func (s *StoppedState) Handle(context *Context) string {
context.SetState(&StartState{})
return "Process is stopped"
}
// 使用示例
func main() {
// 创建上下文,初始状态为StartState
context := NewContext(&StartState{})
// 执行请求,观察状态变化
for i := 0; i < 10; i++ {
result := context.Request()
fmt.Printf("Action %d: %s\n", i+1, result)
}
}
8.2 订单处理状态模式
以下是一个更实际的例子,展示订单处理流程中的状态模式应用:
// 订单状态接口
type OrderState interface {
ProcessOrder(context *OrderContext) error
CancelOrder(context *OrderContext) error
GetStatus() string
}
// 订单上下文
type OrderContext struct {
state OrderState
orderID string
customerID string
items []string
createdAt time.Time
updatedAt time.Time
}
func NewOrder(orderID, customerID string, items []string) *OrderContext {
order := &OrderContext{
orderID: orderID,
customerID: customerID,
items: items,
createdAt: time.Now(),
updatedAt: time.Now(),
}
// 设置初始状态为"新建"
order.state = &NewOrderState{}
return order
}
func (c *OrderContext) SetState(state OrderState) {
c.state = state
c.updatedAt = time.Now()
}
func (c *OrderContext) ProcessOrder() error {
return c.state.ProcessOrder(c)
}
func (c *OrderContext) CancelOrder() error {
return c.state.CancelOrder(c)
}
func (c *OrderContext) GetStatus() string {
return c.state.GetStatus()
}
// 新订单状态
type NewOrderState struct{}
func (s *NewOrderState) ProcessOrder(context *OrderContext) error {
// 处理逻辑...
fmt.Printf("Processing new order %s\n", context.orderID)
// 转换到"已支付"状态
context.SetState(&PaidOrderState{})
return nil
}
func (s *NewOrderState) CancelOrder(context *OrderContext) error {
// 取消逻辑...
fmt.Printf("Canceling new order %s\n", context.orderID)
// 转换到"已取消"状态
context.SetState(&CanceledOrderState{})
return nil
}
func (s *NewOrderState) GetStatus() string {
return "NEW"
}
// 已支付状态
type PaidOrderState struct{}
func (s *PaidOrderState) ProcessOrder(context *OrderContext) error {
// 处理逻辑...
fmt.Printf("Processing paid order %s, preparing shipment\n", context.orderID)
// 转换到"配送中"状态
context.SetState(&ShippingOrderState{})
return nil
}
func (s *PaidOrderState) CancelOrder(context *OrderContext) error {
// 取消逻辑...
fmt.Printf("Canceling paid order %s, initiating refund\n", context.orderID)
// 转换到"已退款"状态
context.SetState(&RefundedOrderState{})
return nil
}
func (s *PaidOrderState) GetStatus() string {
return "PAID"
}
// 配送中状态
type ShippingOrderState struct{}
func (s *ShippingOrderState) ProcessOrder(context *OrderContext) error {
// 处理逻辑...
fmt.Printf("Delivering order %s\n", context.orderID)
// 转换到"已完成"状态
context.SetState(&CompletedOrderState{})
return nil
}
func (s *ShippingOrderState) CancelOrder(context *OrderContext) error {
// 配送中不能直接取消
return fmt.Errorf("cannot cancel order %s that is already shipping", context.orderID)
}
func (s *ShippingOrderState) GetStatus() string {
return "SHIPPING"
}
// 已完成状态
type CompletedOrderState struct{}
func (s *CompletedOrderState) ProcessOrder(context *OrderContext) error {
// 已完成的订单不能再处理
return fmt.Errorf("order %s is already completed", context.orderID)
}
func (s *CompletedOrderState) CancelOrder(context *OrderContext) error {
// 已完成的订单不能取消
return fmt.Errorf("cannot cancel order %s that is already completed", context.orderID)
}
func (s *CompletedOrderState) GetStatus() string {
return "COMPLETED"
}
// 已取消状态
type CanceledOrderState struct{}
func (s *CanceledOrderState) ProcessOrder(context *OrderContext) error {
// 已取消的订单不能处理
return fmt.Errorf("cannot process order %s that is already canceled", context.orderID)
}
func (s *CanceledOrderState) CancelOrder(context *OrderContext) error {
// 已经取消了
return fmt.Errorf("order %s is already canceled", context.orderID)
}
func (s *CanceledOrderState) GetStatus() string {
return "CANCELED"
}
// 已退款状态
type RefundedOrderState struct{}
func (s *RefundedOrderState) ProcessOrder(context *OrderContext) error {
// 已退款的订单不能处理
return fmt.Errorf("cannot process order %s that is already refunded", context.orderID)
}
func (s *RefundedOrderState) CancelOrder(context *OrderContext) error {
// 已经退款了
return fmt.Errorf("order %s is already refunded", context.orderID)
}
func (s *RefundedOrderState) GetStatus() string {
return "REFUNDED"
}
// 使用示例
func main() {
// 创建新订单
order := NewOrder("ORD-12345", "CUST-6789", []string{"Book", "Pen", "Notebook"})
// 打印初始状态
fmt.Printf("Initial order status: %s\n", order.GetStatus())
// 处理订单
err := order.ProcessOrder()
if err != nil {
fmt.Printf("Error: %v\n", err)
}
fmt.Printf("Order status after processing: %s\n", order.GetStatus())
// 继续处理
err = order.ProcessOrder()
if err != nil {
fmt.Printf("Error: %v\n", err)
}
fmt.Printf("Order status after shipping: %s\n", order.GetStatus())
// 尝试取消已配送的订单
err = order.CancelOrder()
if err != nil {
fmt.Printf("Error: %v\n", err)
}
// 创建另一个订单并取消
order2 := NewOrder("ORD-54321", "CUST-9876", []string{"Laptop", "Mouse"})
fmt.Printf("\nNew order status: %s\n", order2.GetStatus())
err = order2.CancelOrder()
if err != nil {
fmt.Printf("Error: %v\n", err)
}
fmt.Printf("Order status after cancellation: %s\n", order2.GetStatus())
// 尝试处理已取消的订单
err = order2.ProcessOrder()
if err != nil {
fmt.Printf("Error: %v\n", err)
}
}
8.3 状态模式的应用场景
状态模式适用于以下场景:
- 对象行为取决于其状态:对象根据状态执行不同的行为。
- 包含大量与状态相关的条件语句:使用状态模式可以消除复杂的条件分支。
- 状态转换有规律:状态转换逻辑可以封装在状态类中。
- 状态机实现:适合实现有限状态机。
在Go中,状态模式常用于工作流系统、订单处理、游戏开发等需要状态管理的场景。
9. 其他行为型模式
除了上述详细介绍的模式外,还有几种重要的行为型模式值得了解:
9.1 访问者模式(Visitor Pattern)
访问者模式表示一个作用于某对象结构中的各元素的操作,它使你可以在不改变元素类的前提下定义作用于这些元素的新操作。在Go中,由于缺乏方法重载,访问者模式通常通过类型断言或类型开关实现。
// 元素接口
type Element interface {
Accept(visitor Visitor)
}
// 访问者接口
type Visitor interface {
VisitCircle(circle *Circle)
VisitRectangle(rectangle *Rectangle)
VisitTriangle(triangle *Triangle)
}
// 具体元素:圆形
type Circle struct {
Radius float64
}
func (c *Circle) Accept(visitor Visitor) {
visitor.VisitCircle(c)
}
// 具体元素:矩形
type Rectangle struct {
Width float64
Height float64
}
func (r *Rectangle) Accept(visitor Visitor) {
visitor.VisitRectangle(r)
}
// 具体元素:三角形
type Triangle struct {
Base float64
Height float64
}
func (t *Triangle) Accept(visitor Visitor) {
visitor.VisitTriangle(t)
}
// 具体访问者:面积计算
type AreaVisitor struct {
totalArea float64
}
func (v *AreaVisitor) VisitCircle(circle *Circle) {
area := math.Pi * circle.Radius * circle.Radius
fmt.Printf("Circle area: %.2f\n", area)
v.totalArea += area
}
func (v *AreaVisitor) VisitRectangle(rectangle *Rectangle) {
area := rectangle.Width * rectangle.Height
fmt.Printf("Rectangle area: %.2f\n", area)
v.totalArea += area
}
func (v *AreaVisitor) VisitTriangle(triangle *Triangle) {
area := 0.5 * triangle.Base * triangle.Height
fmt.Printf("Triangle area: %.2f\n", area)
v.totalArea += area
}
func (v *AreaVisitor) TotalArea() float64 {
return v.totalArea
}
// 具体访问者:周长计算
type PerimeterVisitor struct {
totalPerimeter float64
}
func (v *PerimeterVisitor) VisitCircle(circle *Circle) {
perimeter := 2 * math.Pi * circle.Radius
fmt.Printf("Circle perimeter: %.2f\n", perimeter)
v.totalPerimeter += perimeter
}
func (v *PerimeterVisitor) VisitRectangle(rectangle *Rectangle) {
perimeter := 2 * (rectangle.Width + rectangle.Height)
fmt.Printf("Rectangle perimeter: %.2f\n", perimeter)
v.totalPerimeter += perimeter
}
func (v *PerimeterVisitor) VisitTriangle(triangle *Triangle) {
// 简化计算,假设是等边三角形
side := math.Sqrt(triangle.Base*triangle.Base + triangle.Height*triangle.Height)
perimeter := triangle.Base + 2*side
fmt.Printf("Triangle perimeter: %.2f\n", perimeter)
v.totalPerimeter += perimeter
}
func (v *PerimeterVisitor) TotalPerimeter() float64 {
return v.totalPerimeter
}
// 使用示例
func main() {
// 创建形状
circle := &Circle{Radius: 5}
rectangle := &Rectangle{Width: 4, Height: 6}
triangle := &Triangle{Base: 3, Height: 4}
// 将形状添加到集合
shapes := []Element{circle, rectangle, triangle}
// 创建面积访问者
areaVisitor := &AreaVisitor{}
// 访问所有形状计算面积
for _, shape := range shapes {
shape.Accept(areaVisitor)
}
fmt.Printf("Total area: %.2f\n\n", areaVisitor.TotalArea())
// 创建周长访问者
perimeterVisitor := &PerimeterVisitor{}
// 访问所有形状计算周长
for _, shape := range shapes {
shape.Accept(perimeterVisitor)
}
fmt.Printf("Total perimeter: %.2f\n", perimeterVisitor.TotalPerimeter())
}
9.2 备忘录模式(Memento Pattern)
备忘录模式在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以便以后当需要时能将该对象恢复到原先保存的状态。
// 备忘录
type EditorMemento struct {
content string
}
func NewEditorMemento(content string) *EditorMemento {
return &EditorMemento{content: content}
}
func (m *EditorMemento) GetContent() string {
return m.content
}
// 发起人
type Editor struct {
content string
}
func (e *Editor) Type(text string) {
e.content += text
}
func (e *Editor) GetContent() string {
return e.content
}
func (e *Editor) Save() *EditorMemento {
return NewEditorMemento(e.content)
}
func (e *Editor) Restore(memento *EditorMemento) {
e.content = memento.GetContent()
}
// 管理者
type History struct {
mementos []*EditorMemento
}
func NewHistory() *History {
return &History{
mementos: make([]*EditorMemento, 0),
}
}
func (h *History) Push(memento *EditorMemento) {
h.mementos = append(h.mementos, memento)
}
func (h *History) Pop() *EditorMemento {
if len(h.mementos) == 0 {
return nil
}
lastIndex := len(h.mementos) - 1
memento := h.mementos[lastIndex]
h.mementos = h.mementos[:lastIndex]
return memento
}
// 使用示例
func main() {
editor := &Editor{}
history := NewHistory()
// 编辑文本
editor.Type("Hello")
fmt.Printf("Current content: %s\n", editor.GetContent())
// 保存状态
history.Push(editor.Save())
// 继续编辑
editor.Type(", World!")
fmt.Printf("Current content: %s\n", editor.GetContent())
// 保存状态
history.Push(editor.Save())
// 继续编辑
editor.Type(" How are you?")
fmt.Printf("Current content: %s\n", editor.GetContent())
// 撤销
if memento := history.Pop(); memento != nil {
editor.Restore(memento)
}
fmt.Printf("After first undo: %s\n", editor.GetContent())
// 再次撤销
if memento := history.Pop(); memento != nil {
editor.Restore(memento)
}
fmt.Printf("After second undo: %s\n", editor.GetContent())
}
9.3 中介者模式(Mediator Pattern)
中介者模式用一个中介对象来封装一系列的对象交互,中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。
// 中介者接口
type ChatMediator interface {
SendMessage(message string, user User)
AddUser(user User)
}
// 用户接口
type User interface {
Send(message string)
Receive(message string)
GetName() string
}
// 具体中介者
type ChatRoom struct {
users []User
}
func NewChatRoom() *ChatRoom {
return &ChatRoom{
users: make([]User, 0),
}
}
func (m *ChatRoom) AddUser(user User) {
m.users = append(m.users, user)
fmt.Printf("%s joined the chat\n", user.GetName())
}
func (m *ChatRoom) SendMessage(message string, sender User) {
for _, user := range m.users {
// 不要发送给发送者自己
if user.GetName() != sender.GetName() {
user.Receive(fmt.Sprintf("[%s]: %s", sender.GetName(), message))
}
}
}
// 具体用户
type ChatUser struct {
name string
mediator ChatMediator
}
func NewChatUser(name string, mediator ChatMediator) *ChatUser {
user := &ChatUser{
name: name,
mediator: mediator,
}
mediator.AddUser(user)
return user
}
func (u *ChatUser) Send(message string) {
fmt.Printf("%s is sending: %s\n", u.name, message)
u.mediator.SendMessage(message, u)
}
func (u *ChatUser) Receive(message string) {
fmt.Printf("%s received: %s\n", u.name, message)
}
func (u *ChatUser) GetName() string {
return u.name
}
// 使用示例
func main() {
chatRoom := NewChatRoom()
alice := NewChatUser("Alice", chatRoom)
bob := NewChatUser("Bob", chatRoom)
charlie := NewChatUser("Charlie", chatRoom)
alice.Send("Hi everyone!")
bob.Send("Hey Alice, how are you?")
charlie.Send("Hello to both of you!")
}
9.4 解释器模式(Interpreter Pattern)
解释器模式提供了评估语言的语法或表达式的方式,它属于行为型模式。这种模式实现了一个表达式接口,该接口解释一个特定的上下文。
// 表达式接口
type Expression interface {
Interpret() int
}
// 数字表达式
type NumberExpression struct {
value int
}
func NewNumberExpression(value int) *NumberExpression {
return &NumberExpression{value: value}
}
func (e *NumberExpression) Interpret() int {
return e.value
}
// 加法表达式
type AddExpression struct {
left Expression
right Expression
}
func NewAddExpression(left, right Expression) *AddExpression {
return &AddExpression{
left: left,
right: right,
}
}
func (e *AddExpression) Interpret() int {
return e.left.Interpret() + e.right.Interpret()
}
// 减法表达式
type SubtractExpression struct {
left Expression
right Expression
}
func NewSubtractExpression(left, right Expression) *SubtractExpression {
return &SubtractExpression{
left: left,
right: right,
}
}
func (e *SubtractExpression) Interpret() int {
return e.left.Interpret() - e.right.Interpret()
}
// 使用示例
func main() {
// 解释 (3 + 2) - 1
expression := NewSubtractExpression(
NewAddExpression(
NewNumberExpression(3),
NewNumberExpression(2),
),
NewNumberExpression(1),
)
result := expression.Interpret()
fmt.Printf("(3 + 2) - 1 = %d\n", result)
// 解释 5 - (2 + 1)
expression2 := NewSubtractExpression(
NewNumberExpression(5),
NewAddExpression(
NewNumberExpression(2),
NewNumberExpression(1),
),
)
result2 := expression2.Interpret()
fmt.Printf("5 - (2 + 1) = %d\n", result2)
}
10. Go中行为模式的最佳实践
在Go中应用行为型模式时,有一些特有的最佳实践:
10.1 结合Go的并发特性
Go的goroutine和channel为实现某些行为型模式提供了独特的方式,例如:
- 使用channel实现观察者模式
- 使用goroutine池实现命令模式中的命令队列
- 在责任链模式中使用channel连接处理器
// 使用channel和goroutine实现命令队列
type CommandQueue struct {
queue chan Command
done chan struct{}
wg sync.WaitGroup
workers int
}
func NewCommandQueue(workers int) *CommandQueue {
q := &CommandQueue{
queue: make(chan Command, 100),
done: make(chan struct{}),
workers: workers,
}
q.start()
return q
}
func (q *CommandQueue) start() {
q.wg.Add(q.workers)
for i := 0; i < q.workers; i++ {
go q.worker()
}
}
func (q *CommandQueue) worker() {
defer q.wg.Done()
for {
select {
case cmd := <-q.queue:
cmd.Execute()
case <-q.done:
return
}
}
}
func (q *CommandQueue) Add(cmd Command) {
q.queue <- cmd
}
func (q *CommandQueue) Stop() {
close(q.done)
q.wg.Wait()
}
10.2 优先使用组合而非继承
在Go中实现行为型模式时,应该优先使用组合而非继承:
// 不好的做法:尝试模拟继承
type AbstractHandler struct {
nextHandler *AbstractHandler
}
// 好的做法:使用组合和接口
type Handler interface {
Handle(request string) (string, bool)
}
type RequestHandler struct {
next Handler
}
func (h *RequestHandler) SetNext(next Handler) {
h.next = next
}
10.3 利用函数类型和闭包
Go的函数类型和闭包可以让行为型模式的实现更加简洁:
// 使用函数类型简化策略模式
type SortStrategy func(data []int)
func BubbleSort(data []int) {
// 冒泡排序实现
}
func QuickSort(data []int) {
// 快速排序实现
}
// 上下文
type Sorter struct {
strategy SortStrategy
}
func (s *Sorter) SetStrategy(strategy SortStrategy) {
s.strategy = strategy
}
func (s *Sorter) Sort(data []int) {
s.strategy(data)
}
10.4 避免过度设计
在Go中应用设计模式时要保持克制,避免过度设计:
// 过度设计的例子
type AddOperation struct{}
func (o *AddOperation) Execute(a, b int) int { return a + b }
type SubtractOperation struct{}
func (o *SubtractOperation) Execute(a, b int) int { return a - b }
type MultiplyOperation struct{}
func (o *MultiplyOperation) Execute(a, b int) int { return a * b }
type DivideOperation struct{}
func (o *DivideOperation) Execute(a, b int) int { return a / b }
// 简单的函数就足够了
func Add(a, b int) int { return a + b }
func Subtract(a, b int) int { return a - b }
func Multiply(a, b int) int { return a * b }
func Divide(a, b int) int { return a / b }
总结
在本文中,我们深入探讨了行为型设计模式在Go中的实现。行为型模式关注对象之间的通信和交互方式,帮助我们设计出灵活、可扩展的系统。
我们详细介绍了观察者模式、策略模式、命令模式、责任链模式、模板方法模式、迭代器模式和状态模式等核心行为型模式,并简要介绍了访问者模式、备忘录模式、中介者模式和解释器模式。对于每种模式,我们都提供了基本实现和Go特有的实现方式,以及应用场景和最佳实践。
通过学习这些模式,我们可以看到:
- Go语言的特性(如接口、函数类型、goroutine和channel)为实现行为型模式提供了独特的方式。
- 与传统面向对象语言相比,Go中的行为型模式实现通常更加简洁和灵活。
- 函数式编程风格和组合优于继承的原则使得Go的设计模式实现更加符合Go语言的设计哲学。
在实际应用中,我们应该根据具体需求选择合适的模式,避免过度设计,保持代码的简洁性和可维护性。记住,设计模式是工具而非目标,最终目的是构建出优雅、高效、可维护的软件系统。
结合上一篇文章中介绍的创建型模式和结构型模式,我们现在已经全面了解了Go中的设计模式应用。这些知识将帮助我们在实际工作中更好地设计和实现Go项目。
👨💻 关于作者与Gopher部落
"Gopher部落"专注于Go语言技术分享,提供从入门到精通的完整学习路线。
🌟 为什么关注我们?
- 系统化学习路径:本系列50篇文章循序渐进,带你完整掌握Go开发
- 实战驱动教学:理论结合实践,每篇文章都有可操作的代码示例
- 持续更新内容:定期分享最新Go生态技术动态与大厂实践经验
- 专业技术社区:加入我们的技术交流群,与众多Go开发者共同成长
📱 关注方式
- 微信公众号:搜索 “Gopher部落” 或 “GopherTribe”
- 优快云专栏:点击页面右上角"关注"按钮
💡 读者福利
关注公众号回复 “行为模式” 即可获取:
- Go行为型设计模式完整代码示例
- 行为型模式应用场景速查表
- Go项目架构设计实战指南
期待与您在Go语言的学习旅程中共同成长!
Go语言中行为型设计模式的应用

被折叠的 条评论
为什么被折叠?



