常见的设计模式,如 单例模式、工厂模式、策略模式、观察者模式、代理模式、装饰器模式 和 适配器模式 都可以在 Go 中实现,适用于不同的开发需求。
这些设计模式不仅能帮助你编写结构清晰、可维护的代码,还能让你更好地应对复杂的编程问题。
简介:
Go 的单例模式(Singleton Pattern)适用于某些需要确保一个类(或结构体)在整个应用程序中只有一个实例的场景。通常情况下,单例模式用于全局共享资源、缓存、日志管理、数据库连接等场景,避免了不必要的对象创建和资源浪费。
使用场景:
优点:
sync.Once
可以确保在并发环境下,单例对象只被创建一次,避免竞态条件和数据竞争。缺点:
实现:
package main
import (
"fmt"
"sync"
)
type Singleton struct {
// 可能包含一些属性
}
var instance *Singleton
var once sync.Once
func GetInstance() *Singleton {
once.Do(func() {
instance = &Singleton{}
})
return instance
}
func main() {
s1 := GetInstance()
s2 := GetInstance()
fmt.Println(s1 == s2) // true
}
简介:
工厂模式用于创建对象的实例,但不暴露具体的创建逻辑,它通过接口来解耦对象的创建和使用。
使用场景:
优点:
缺点:
实现:
简单工厂模式:适用对象较少创建、逻辑简单的场景。
package main
import (
"fmt"
)
// 通知接口
type Notifier interface {
Notify(message string)
}
// 邮件通知
type EmailNotifier struct{}
func (e *EmailNotifier) Notify(message string) {
fmt.Println("Email Notification:", message)
}
// 短信通知
type SMSNotifier struct{}
func (s *SMSNotifier) Notify(message string) {
fmt.Println("SMS Notification:", message)
}
// 工厂函数
func NewNotifier(notifyType string) Notifier {
switch notifyType {
case "email":
return &EmailNotifier{}
case "sms":
return &SMSNotifier{}
default:
return nil
}
}
func main() {
notifier := NewNotifier("email")
if notifier != nil {
notifier.Notify("Hello via Email!")
}
notifier = NewNotifier("sms")
if notifier != nil {
notifier.Notify("Hello via SMS!")
}
}
简介:
一种行为设计模式,旨在将一组算法封装到独立的类中,使它们可以互相替换,通过使用策略模式,算法的变化不会影响使用算法的上下文代码。策略模式在Go语言中尤为常见,因为接口和结构体组合的特性使得实现即灵活又高效。
使用场景:
if-else
或switch
判断的地方。优点:
缺点:
实现:
package main
import "fmt"
// 策略接口
type Strategy interface {
Execute(a, b int) int
}
// 加法策略
type AddStrategy struct{}
func (s AddStrategy) Execute(a, b int) int {
return a + b
}
// 乘法策略
type MultiplyStrategy struct{}
func (s MultiplyStrategy) Execute(a, b int) int {
return a * b
}
// 上下文结构体
type Context struct {
strategy Strategy
}
// 设置策略
func (c *Context) SetStrategy(strategy Strategy) {
c.strategy = strategy
}
// 执行策略
func (c *Context) ExecuteStrategy(a, b int) int {
return c.strategy.Execute(a, b)
}
func main() {
context := Context{}
// 使用加法策略
context.SetStrategy(AddStrategy{})
result := context.ExecuteStrategy(5, 3)
fmt.Println("加法策略结果:", result) // 输出:8
// 使用乘法策略
context.SetStrategy(MultiplyStrategy{})
result = context.ExecuteStrategy(5, 3)
fmt.Println("乘法策略结果:", result) // 输出:15
}
简介:
一种行为设计模式,允许对象在其状态发生更改时通知其他依赖对象。它定义了一种一对多的依赖关系,一个对象(主题/被观察者)状态变化时,所有依赖者(观察者)都会收到通知并自动更新。
使用场景:
优点:
缺点:
实现:
package main
import "fmt"
// 观察者接口
type Observer interface {
Update(message string)
}
// 主题接口
type Subject interface {
Register(observer Observer)
Unregister(observer Observer)
NotifyAll(message string)
}
// 具体主题
type NewsPublisher struct {
observers []Observer
}
// 注册观察者
func (n *NewsPublisher) Register(observer Observer) {
n.observers = append(n.observers, observer)
}
// 注销观察者
func (n *NewsPublisher) Unregister(observer Observer) {
for i, obs := range n.observers {
if obs == observer {
n.observers = append(n.observers[:i], n.observers[i+1:]...)
break
}
}
}
// 通知所有观察者
func (n *NewsPublisher) NotifyAll(message string) {
for _, observer := range n.observers {
observer.Update(message)
}
}
// 具体观察者
type NewsSubscriber struct {
name string
}
// 接收更新通知
func (n *NewsSubscriber) Update(message string) {
fmt.Printf("[%s] 收到新闻更新:%s\n", n.name, message)
}
// 创建新的观察者
func NewSubscriber(name string) *NewsSubscriber {
return &NewsSubscriber{name: name}
}
func main() {
// 创建新闻发布者(主题) 隐式使用
// var publisher Subject = &NewsPublisher{}
publisher := &NewsPublisher{}
// 创建观察者(订阅者)
sub1 := NewSubscriber("Alice")
sub2 := NewSubscriber("Bob")
sub3 := NewSubscriber("Charlie")
// 注册观察者
publisher.Register(sub1)
publisher.Register(sub2)
publisher.Register(sub3)
// 发布新闻更新
publisher.NotifyAll("Go 1.21 发布了!")
// 注销一个观察者
publisher.Unregister(sub2)
// 再次发布新闻
publisher.NotifyAll("Go 1.22 即将发布!")
}
简介:
一种结构型设计模式,它通过一个代理对象来控制对目标对象的访问。代理对象可以在客户端和真实对象之间进行一些操作,比如权限控制、懒加载、日志记录、缓存等,特别适合增强现有类的功能而无需修改原有代码。
使用场景:
优点:
缺点:
实现:
package main
import (
"fmt"
"time"
)
// 抽象接口(Subject)
type BankAccount interface {
Deposit(amount float64)
Withdraw(amount float64)
GetBalance() float64
}
// 实际对象(RealSubject):银行账户
type RealBankAccount struct {
balance float64
}
func (r *RealBankAccount) Deposit(amount float64) {
r.balance += amount
fmt.Printf("存入:%.2f 元,当前余额:%.2f 元\n", amount, r.balance)
}
func (r *RealBankAccount) Withdraw(amount float64) {
if amount > r.balance {
fmt.Println("余额不足,取款失败!")
return
}
r.balance -= amount
fmt.Printf("取出:%.2f 元,当前余额:%.2f 元\n", amount, r.balance)
}
func (r *RealBankAccount) GetBalance() float64 {
return r.balance
}
// 代理对象(Proxy):日志代理
type LoggingProxy struct {
realAccount BankAccount
}
func NewLoggingProxy(realAccount BankAccount) *LoggingProxy {
return &LoggingProxy{realAccount: realAccount}
}
func (p *LoggingProxy) Deposit(amount float64) {
fmt.Printf("[%s] 正在进行存款操作...\n", time.Now().Format("2006-01-02 15:04:05"))
p.realAccount.Deposit(amount)
}
func (p *LoggingProxy) Withdraw(amount float64) {
fmt.Printf("[%s] 正在进行取款操作...\n", time.Now().Format("2006-01-02 15:04:05"))
p.realAccount.Withdraw(amount)
}
func (p *LoggingProxy) GetBalance() float64 {
balance := p.realAccount.GetBalance()
fmt.Printf("[%s] 查询余额:%.2f 元\n", time.Now().Format("2006-01-02 15:04:05"), balance)
return balance
}
// 客户端代码
func main() {
// 创建实际银行账户
realAccount := &RealBankAccount{}
// 使用代理来包装实际账户
proxy := NewLoggingProxy(realAccount)
// 通过代理进行操作
proxy.Deposit(1000)
proxy.Withdraw(300)
proxy.GetBalance()
}
简介:
一种结构型设计模式,允许在不修改对象结构的情况下动态地为对象添加新功能。
使用场景:
装饰器模式的核心思想:
优点:
缺点:
实现:
package main
import (
"fmt"
)
// Component 接口:咖啡饮品
type Beverage interface {
GetDescription() string
Cost() float64
}
// 具体组件:基础咖啡
type Espresso struct{}
func (e *Espresso) GetDescription() string {
return "Espresso"
}
func (e *Espresso) Cost() float64 {
return 15.0
}
// 装饰器基类:实现 Beverage 接口
type CondimentDecorator struct {
beverage Beverage
}
func (c *CondimentDecorator) GetDescription() string {
return c.beverage.GetDescription()
}
func (c *CondimentDecorator) Cost() float64 {
return c.beverage.Cost()
}
// 具体装饰器:牛奶
type Milk struct {
CondimentDecorator
}
func NewMilk(beverage Beverage) *Milk {
return &Milk{CondimentDecorator{beverage}}
}
func (m *Milk) GetDescription() string {
return m.beverage.GetDescription() + ", Milk"
}
func (m *Milk) Cost() float64 {
return m.beverage.Cost() + 3.5
}
// 具体装饰器:糖
type Sugar struct {
CondimentDecorator
}
func NewSugar(beverage Beverage) *Sugar {
return &Sugar{CondimentDecorator{beverage}}
}
func (s *Sugar) GetDescription() string {
return s.beverage.GetDescription() + ", Sugar"
}
func (s *Sugar) Cost() float64 {
return s.beverage.Cost() + 1.0
}
// 客户端代码
func main() {
// 创建基础咖啡
var beverage Beverage = &Espresso{}
fmt.Printf("饮品:%s,价格:%.2f 元\n", beverage.GetDescription(), beverage.Cost())
// 加牛奶
beverage = NewMilk(beverage)
fmt.Printf("饮品:%s,价格:%.2f 元\n", beverage.GetDescription(), beverage.Cost())
// 再加糖
beverage = NewSugar(beverage)
fmt.Printf("饮品:%s,价格:%.2f 元\n", beverage.GetDescription(), beverage.Cost())
}
特性 | 装饰器模式 | 代理模式 |
---|---|---|
主要目的 | 动态扩展功能 | 控制对对象的访问 |
结构特点 | 组合多个装饰器形成链 | 代理对象持有实际对象的引用 |
典型应用场景 | 日志、性能监控、权限校验、增强对象功能 | 远程代理、虚拟代理、安全代理、缓存代理 |
简介:
一种结构型设计模式,它通过两个不兼容的接口提供一个适配器,使得它们能够一起工作。适配器模式可以将一个接口转换为客户端期望的另一个接口,目的时让不兼容的接口能过够合作。
使用场景:
适配器模式的核心思想
优点:
缺点:
实现:
package main
import "fmt"
// 目标接口(Target):要求的电源接口
type PowerOutlet interface {
SupplyPower() string
}
// 源接口(Adaptee):我们现有的电源接口
type TwoPinSocket struct{}
func (s *TwoPinSocket) ProvidePower() string {
return "提供 220V 电流"
}
// 适配器(Adapter):将现有电源接口转换为目标接口
type Adapter struct {
socket *TwoPinSocket
}
// 适配器的方法:使其实现目标接口
func (a *Adapter) SupplyPower() string {
return a.socket.ProvidePower()
}
// 客户端代码
func main() {
// 使用现有的 2 针电源插座(不符合目标接口)
twoPinSocket := &TwoPinSocket{}
// 通过适配器将其转换为目标接口
adapter := &Adapter{socket: twoPinSocket}
// 客户端通过目标接口使用适配后的电源
fmt.Println("设备电源:", adapter.SupplyPower())
}
特性 | 适配器模式 | 代理模式 |
---|---|---|
主要目的 | 使接口兼容并进行转换,适配不同接口的类 | 控制对目标对象的访问,通常是延迟或虚拟化操作。 |
结构特点 | 客户端和目标接口之间通过适配器进行转换 | 代理对象持有实际对象的引用,进行控制访问 |
典型应用场景 | 使得不兼容的类能够协作,转换接口 | 控制对实际对象的访问(如延迟加载、远程调用等) |