IT评测·应用市场-qidao123.com技术社区

标题: Go常用的设计模式 [打印本页]

作者: 海哥    时间: 2025-3-28 16:55
标题: Go常用的设计模式
Go常用的设计模式

常见的设计模式,如 单例模式工厂模式策略模式观察者模式署理模式装饰器模式适配器模式 都可以在 Go 中实现,适用于差别的开辟需求。
这些设计模式不仅能帮助你编写结构清楚、可维护的代码,还能让你更好地应对复杂的编程题目。
一、单例模式(Singleton)

简介:
​        Go 的单例模式(Singleton Pattern)适用于某些必要确保一个类(或结构体)在整个应用步伐中只有一个实例的场景。通常环境下,单例模式用于全局共享资源、缓存、日记管理、数据库毗连等场景,制止了不必要的对象创建和资源浪费。
使用场景:
优点:
缺点:
实现:
  1. package main
  2. import (
  3.         "fmt"
  4.         "sync"
  5. )
  6. type Singleton struct {
  7.         // 可能包含一些属性
  8. }
  9. var instance *Singleton
  10. var once sync.Once
  11. func GetInstance() *Singleton {
  12.         once.Do(func() {
  13.                 instance = &Singleton{}
  14.         })
  15.         return instance
  16. }
  17. func main() {
  18.         s1 := GetInstance()
  19.         s2 := GetInstance()
  20.         fmt.Println(s1 == s2) // true
  21. }
复制代码
二、工厂模式(Factory)

简介:
​        工厂模式用于创建对象的实例,但不暴露具体的创建逻辑,它通过接口来解耦对象的创建和使用。
使用场景:
优点:
缺点:
实现:
简单工厂模式:适用对象较少创建、逻辑简单的场景。
  1. package main
  2. import (
  3.         "fmt"
  4. )
  5. // 通知接口
  6. type Notifier interface {
  7.         Notify(message string)
  8. }
  9. // 邮件通知
  10. type EmailNotifier struct{}
  11. func (e *EmailNotifier) Notify(message string) {
  12.         fmt.Println("Email Notification:", message)
  13. }
  14. // 短信通知
  15. type SMSNotifier struct{}
  16. func (s *SMSNotifier) Notify(message string) {
  17.         fmt.Println("SMS Notification:", message)
  18. }
  19. // 工厂函数
  20. func NewNotifier(notifyType string) Notifier {
  21.         switch notifyType {
  22.         case "email":
  23.                 return &EmailNotifier{}
  24.         case "sms":
  25.                 return &SMSNotifier{}
  26.         default:
  27.                 return nil
  28.         }
  29. }
  30. func main() {
  31.         notifier := NewNotifier("email")
  32.         if notifier != nil {
  33.                 notifier.Notify("Hello via Email!")
  34.         }
  35.         notifier = NewNotifier("sms")
  36.         if notifier != nil {
  37.                 notifier.Notify("Hello via SMS!")
  38.         }
  39. }
复制代码
三、策略模式(Strategy Pattern)

简介:
​        一种行为设计模式,旨在将一组算法封装到独立的类中,使它们可以相互更换,通过使用策略模式,算法的变化不会影响使用算法的上下文代码。策略模式在Go语言中尤为常见,因为接口和结构体组合的特性使得实现即灵活又高效。
使用场景:
优点:
缺点:
实现:
  1. package main
  2. import "fmt"
  3. // 策略接口
  4. type Strategy interface {
  5.         Execute(a, b int) int
  6. }
  7. // 加法策略
  8. type AddStrategy struct{}
  9. func (s AddStrategy) Execute(a, b int) int {
  10.         return a + b
  11. }
  12. // 乘法策略
  13. type MultiplyStrategy struct{}
  14. func (s MultiplyStrategy) Execute(a, b int) int {
  15.         return a * b
  16. }
  17. // 上下文结构体
  18. type Context struct {
  19.         strategy Strategy
  20. }
  21. // 设置策略
  22. func (c *Context) SetStrategy(strategy Strategy) {
  23.         c.strategy = strategy
  24. }
  25. // 执行策略
  26. func (c *Context) ExecuteStrategy(a, b int) int {
  27.         return c.strategy.Execute(a, b)
  28. }
  29. func main() {
  30.         context := Context{}
  31.         // 使用加法策略
  32.         context.SetStrategy(AddStrategy{})
  33.         result := context.ExecuteStrategy(5, 3)
  34.         fmt.Println("加法策略结果:", result) // 输出:8
  35.         // 使用乘法策略
  36.         context.SetStrategy(MultiplyStrategy{})
  37.         result = context.ExecuteStrategy(5, 3)
  38.         fmt.Println("乘法策略结果:", result) // 输出:15
  39. }
复制代码
四、观察者模式(Observer Pattern)

简介:
​        一种行为设计模式,允许对象在其状态发生更改时关照其他依赖对象。它定义了一种一对多的依赖关系,一个对象(主题/被观察者)状态变化时,全部依赖者(观察者)都会收到关照并自动更新。
使用场景:
优点:
缺点:
实现:
  1. package main
  2. import "fmt"
  3. // 观察者接口
  4. type Observer interface {
  5.         Update(message string)
  6. }
  7. // 主题接口
  8. type Subject interface {
  9.         Register(observer Observer)
  10.         Unregister(observer Observer)
  11.         NotifyAll(message string)
  12. }
  13. // 具体主题
  14. type NewsPublisher struct {
  15.         observers []Observer
  16. }
  17. // 注册观察者
  18. func (n *NewsPublisher) Register(observer Observer) {
  19.         n.observers = append(n.observers, observer)
  20. }
  21. // 注销观察者
  22. func (n *NewsPublisher) Unregister(observer Observer) {
  23.         for i, obs := range n.observers {
  24.                 if obs == observer {
  25.                         n.observers = append(n.observers[:i], n.observers[i+1:]...)
  26.                         break
  27.                 }
  28.         }
  29. }
  30. // 通知所有观察者
  31. func (n *NewsPublisher) NotifyAll(message string) {
  32.         for _, observer := range n.observers {
  33.                 observer.Update(message)
  34.         }
  35. }
  36. // 具体观察者
  37. type NewsSubscriber struct {
  38.         name string
  39. }
  40. // 接收更新通知
  41. func (n *NewsSubscriber) Update(message string) {
  42.         fmt.Printf("[%s] 收到新闻更新:%s\n", n.name, message)
  43. }
  44. // 创建新的观察者
  45. func NewSubscriber(name string) *NewsSubscriber {
  46.         return &NewsSubscriber{name: name}
  47. }
  48. func main() {
  49.         // 创建新闻发布者(主题) 隐式使用
  50.         // var publisher Subject = &NewsPublisher{}
  51.         publisher := &NewsPublisher{}
  52.         // 创建观察者(订阅者)
  53.         sub1 := NewSubscriber("Alice")
  54.         sub2 := NewSubscriber("Bob")
  55.         sub3 := NewSubscriber("Charlie")
  56.         // 注册观察者
  57.         publisher.Register(sub1)
  58.         publisher.Register(sub2)
  59.         publisher.Register(sub3)
  60.         // 发布新闻更新
  61.         publisher.NotifyAll("Go 1.21 发布了!")
  62.         // 注销一个观察者
  63.         publisher.Unregister(sub2)
  64.         // 再次发布新闻
  65.         publisher.NotifyAll("Go 1.22 即将发布!")
  66. }
复制代码
五、署理模式(Proxy Pattern)

简介:
​        一种结构型设计模式,它通过一个署理对象来控制对目的对象的访问。署理对象可以在客户端和真实对象之间进行一些操纵,好比权限控制、懒加载、日记记录、缓存等,特别适合加强现有类的功能而无需修改原有代码。
使用场景:
优点:
缺点:
实现:
  1. package main
  2. import (
  3.     "fmt"
  4.     "time"
  5. )
  6. // 抽象接口(Subject)
  7. type BankAccount interface {
  8.     Deposit(amount float64)
  9.     Withdraw(amount float64)
  10.     GetBalance() float64
  11. }
  12. // 实际对象(RealSubject):银行账户
  13. type RealBankAccount struct {
  14.     balance float64
  15. }
  16. func (r *RealBankAccount) Deposit(amount float64) {
  17.     r.balance += amount
  18.     fmt.Printf("存入:%.2f 元,当前余额:%.2f 元\n", amount, r.balance)
  19. }
  20. func (r *RealBankAccount) Withdraw(amount float64) {
  21.     if amount > r.balance {
  22.         fmt.Println("余额不足,取款失败!")
  23.         return
  24.     }
  25.     r.balance -= amount
  26.     fmt.Printf("取出:%.2f 元,当前余额:%.2f 元\n", amount, r.balance)
  27. }
  28. func (r *RealBankAccount) GetBalance() float64 {
  29.     return r.balance
  30. }
  31. // 代理对象(Proxy):日志代理
  32. type LoggingProxy struct {
  33.     realAccount BankAccount
  34. }
  35. func NewLoggingProxy(realAccount BankAccount) *LoggingProxy {
  36.     return &LoggingProxy{realAccount: realAccount}
  37. }
  38. func (p *LoggingProxy) Deposit(amount float64) {
  39.     fmt.Printf("[%s] 正在进行存款操作...\n", time.Now().Format("2006-01-02 15:04:05"))
  40.     p.realAccount.Deposit(amount)
  41. }
  42. func (p *LoggingProxy) Withdraw(amount float64) {
  43.     fmt.Printf("[%s] 正在进行取款操作...\n", time.Now().Format("2006-01-02 15:04:05"))
  44.     p.realAccount.Withdraw(amount)
  45. }
  46. func (p *LoggingProxy) GetBalance() float64 {
  47.     balance := p.realAccount.GetBalance()
  48.     fmt.Printf("[%s] 查询余额:%.2f 元\n", time.Now().Format("2006-01-02 15:04:05"), balance)
  49.     return balance
  50. }
  51. // 客户端代码
  52. func main() {
  53.     // 创建实际银行账户
  54.     realAccount := &RealBankAccount{}
  55.     // 使用代理来包装实际账户
  56.     proxy := NewLoggingProxy(realAccount)
  57.     // 通过代理进行操作
  58.     proxy.Deposit(1000)
  59.     proxy.Withdraw(300)
  60.     proxy.GetBalance()
  61. }
复制代码
六、装饰器模式

简介:
​        一种结构型设计模式,允许在不修改对象结构的环境下动态地为对象添加新功能。
使用场景:
装饰器模式的核心思想:
优点:
缺点:
实现:
  1. package main
  2. import (
  3.         "fmt"
  4. )
  5. // Component 接口:咖啡饮品
  6. type Beverage interface {
  7.         GetDescription() string
  8.         Cost() float64
  9. }
  10. // 具体组件:基础咖啡
  11. type Espresso struct{}
  12. func (e *Espresso) GetDescription() string {
  13.         return "Espresso"
  14. }
  15. func (e *Espresso) Cost() float64 {
  16.         return 15.0
  17. }
  18. // 装饰器基类:实现 Beverage 接口
  19. type CondimentDecorator struct {
  20.         beverage Beverage
  21. }
  22. func (c *CondimentDecorator) GetDescription() string {
  23.         return c.beverage.GetDescription()
  24. }
  25. func (c *CondimentDecorator) Cost() float64 {
  26.         return c.beverage.Cost()
  27. }
  28. // 具体装饰器:牛奶
  29. type Milk struct {
  30.         CondimentDecorator
  31. }
  32. func NewMilk(beverage Beverage) *Milk {
  33.         return &Milk{CondimentDecorator{beverage}}
  34. }
  35. func (m *Milk) GetDescription() string {
  36.         return m.beverage.GetDescription() + ", Milk"
  37. }
  38. func (m *Milk) Cost() float64 {
  39.         return m.beverage.Cost() + 3.5
  40. }
  41. // 具体装饰器:糖
  42. type Sugar struct {
  43.         CondimentDecorator
  44. }
  45. func NewSugar(beverage Beverage) *Sugar {
  46.         return &Sugar{CondimentDecorator{beverage}}
  47. }
  48. func (s *Sugar) GetDescription() string {
  49.         return s.beverage.GetDescription() + ", Sugar"
  50. }
  51. func (s *Sugar) Cost() float64 {
  52.         return s.beverage.Cost() + 1.0
  53. }
  54. // 客户端代码
  55. func main() {
  56.         // 创建基础咖啡
  57.         var beverage Beverage = &Espresso{}
  58.         fmt.Printf("饮品:%s,价格:%.2f 元\n", beverage.GetDescription(), beverage.Cost())
  59.         // 加牛奶
  60.         beverage = NewMilk(beverage)
  61.         fmt.Printf("饮品:%s,价格:%.2f 元\n", beverage.GetDescription(), beverage.Cost())
  62.         // 再加糖
  63.         beverage = NewSugar(beverage)
  64.         fmt.Printf("饮品:%s,价格:%.2f 元\n", beverage.GetDescription(), beverage.Cost())
  65. }
复制代码
装饰器模式和署理模式对比

特性装饰器模式署理模式主要目的动态扩展功能控制对对象的访问结构特点组合多个装饰器形成链署理对象持有现实对象的引用典型应用场景日记、性能监控、权限校验、加强对象功能远程署理、虚拟署理、安全署理、缓存署理七、适配器模式(Adapter Pattern)

简介:
​        一种结构型设计模式,它通过两个不兼容的接口提供一个适配器,使得它们可以或许一起工作。适配器模式可以将一个接口转换为客户端盼望的另一个接口,目的时让不兼容的接口能过够相助。
使用场景:
适配器模式的核心思想
优点:
缺点:
实现:
  1. package main
  2. import "fmt"
  3. // 目标接口(Target):要求的电源接口
  4. type PowerOutlet interface {
  5.         SupplyPower() string
  6. }
  7. // 源接口(Adaptee):我们现有的电源接口
  8. type TwoPinSocket struct{}
  9. func (s *TwoPinSocket) ProvidePower() string {
  10.         return "提供 220V 电流"
  11. }
  12. // 适配器(Adapter):将现有电源接口转换为目标接口
  13. type Adapter struct {
  14.         socket *TwoPinSocket
  15. }
  16. // 适配器的方法:使其实现目标接口
  17. func (a *Adapter) SupplyPower() string {
  18.         return a.socket.ProvidePower()
  19. }
  20. // 客户端代码
  21. func main() {
  22.         // 使用现有的 2 针电源插座(不符合目标接口)
  23.         twoPinSocket := &TwoPinSocket{}
  24.         // 通过适配器将其转换为目标接口
  25.         adapter := &Adapter{socket: twoPinSocket}
  26.         // 客户端通过目标接口使用适配后的电源
  27.         fmt.Println("设备电源:", adapter.SupplyPower())
  28. }
复制代码
适配器模式与署理模式的对比

特性适配器模式署理模式主要目的使接口兼容并进行转换,适配差别接口的类控制对目的对象的访问,通常是耽误或虚拟化操纵。结构特点客户端和目的接口之间通过适配器进行转换署理对象持有现实对象的引用,进行控制访问典型应用场景使得不兼容的类可以或许协作,转换接口控制对现实对象的访问(如耽误加载、远程调用等)
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 IT评测·应用市场-qidao123.com技术社区 (https://dis.qidao123.com/) Powered by Discuz! X3.4