《深入理解设计模式》记录

这里只记录了相对常用、面试常问的设计模式。

单例模式

单例模式(Singleton Pattern)是一种创建型设计模式,其核心目标是确保一个类仅有一个实例,并提供全局访问点。它适用于需要全局唯一对象且频繁访问的场景,例如配置管理、线程池、日志记录器等。

单例模式需要注意三点:

  • 私有化构造函数:防止外部通过 new 直接创建实例。
  • 自行创建实例:类内部负责生成唯一实例。
  • 全局访问方法:提供静态方法供外部获取实例。

懒汉模式

特点:延迟实例化,首次调用时创建实例,需处理线程安全问题。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
package singleton

import "sync"

type lazySingleton struct {
  
}

var (
	instance *lazySingleton
  once sync.Once
)

func GetLazyInstance() *lazySingleton {
  once.Do(func() {
    instance = &lazySingleton{}
  })
  return instance
}

饿汉模式

特点:在包加载时直接初始化实例,无需考虑线程安全。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
package singleton

type eagerSingleton struct {

}

var instance = &eagerSingleton{}

func GetEagerInstance() *eagerSingleton {
    return instance
}

懒汉模式的另一实现形式:静态内部类

特点:通过嵌套结构体延迟加载,结合 sync.Once 实现线程安全。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package singleton

import "sync"

type holderSingleton struct {

}

var (
    holderInstance *holderSingleton
    holderOnce     sync.Once
)

// 嵌套结构体(模拟静态内部类)
type holder struct{}

func (h *holder) getInstance() *holderSingleton {
    holderOnce.Do(func() {
        holderInstance = &holderSingleton{}
    })
    return holderInstance
}

// GetHolderInstance 对外暴露访问方法
func GetHolderInstance() *holderSingleton {
    return (&holder{}).getInstance()
}

枚举类

特点:利用 Go 的 init 函数和常量模拟枚举单例。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
package singleton

type enumSingleton struct {
    // 定义单例结构体字段
}

const (
    InstanceKey = "singleton"
)

var instances = make(map[string]interface{})

func init() {
    instances[InstanceKey] = &enumSingleton{}
}

// GetEnumInstance 通过键名获取单例
func GetEnumInstance() *enumSingleton {
    return instances[InstanceKey].(*enumSingleton)
}

工厂模式

工厂模式是一种创建型设计模式,其核心思想是通过工厂类封装对象的创建过程,降低代码耦合度,提升扩展性。

简单工厂模式

特点:由一个工厂类根据参数决定创建哪种具体产品,客户端无需直接实例化对象。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package main

// 产品接口
type Product interface {
    Use() string
}

// 具体产品A
type ConcreteProductA struct{}

func (p *ConcreteProductA) Use() string {
    return "Product A"
}

// 具体产品B
type ConcreteProductB struct{}

func (p *ConcreteProductB) Use() string {
    return "Product B"
}

// 工厂类
type Factory struct{}

func (f *Factory) CreateProduct(typ string) Product {
    switch typ {
    case "A":
        return &ConcreteProductA{}
    case "B":
        return &ConcreteProductB{}
    default:
        return nil
    }
}

// 使用示例
func main() {
    factory := Factory{}
    productA := factory.CreateProduct("A")
    println(productA.Use()) // 输出:Product A
}

工厂方法模式

特点:定义抽象工厂接口,由子类决定实例化的具体产品,符合开闭原则。只有一个抽象产品接口、抽象工厂接口。

适用场景:产品类型较多且可能扩展,需分离创建逻辑与业务逻辑。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
package main

// 产品接口
type Transport interface {
    Deliver() string
}

// 具体产品:卡车
type Truck struct{}

func (t *Truck) Deliver() string {
    return "Delivering by land"
}

// 具体产品:轮船
type Ship struct{}

func (s *Ship) Deliver() string {
    return "Delivering by sea"
}

// 抽象工厂接口
type LogisticsFactory interface {
    CreateTransport() Transport
}

// 卡车工厂
type TruckFactory struct{}

func (tf *TruckFactory) CreateTransport() Transport {
    return &Truck{}
}

// 轮船工厂
type ShipFactory struct{}

func (sf *ShipFactory) CreateTransport() Transport {
    return &Ship{}
}

// 使用示例
func main() {
    truckFactory := &TruckFactory{}
    truck := truckFactory.CreateTransport()
    println(truck.Deliver()) // 输出:Delivering by land
}

抽象工厂模式

特点:创建多个相关或依赖的产品族(如不同品牌的全套产品),强调产品之间的关联性。由多个抽象产品接口、一个抽象工厂接口。 适用场景:需要生产一组配套对象(如不同风格的UI组件、品牌的全套硬件)。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
package main

// 产品接口:手机
type Phone interface {
    Call() string
}

// 华为手机
type HuaweiPhone struct{}

func (h *HuaweiPhone) Call() string {
    return "Huawei phone calling"
}

// 苹果手机
type IPhone struct{}

func (i *IPhone) Call() string {
    return "iPhone calling"
}

// 产品接口:电脑
type Computer interface {
    Work() string
}

// 华为电脑
type HuaweiComputer struct{}

func (h *HuaweiComputer) Work() string {
    return "Huawei computer working"
}

// 苹果电脑
type MacBook struct{}

func (m *MacBook) Work() string {
    return "MacBook working"
}

// 抽象工厂接口
type TechFactory interface {
    CreatePhone() Phone
    CreateComputer() Computer
}

// 华为工厂
type HuaweiFactory struct{}

func (hf *HuaweiFactory) CreatePhone() Phone {
    return &HuaweiPhone{}
}

func (hf *HuaweiFactory) CreateComputer() Computer {
    return &HuaweiComputer{}
}

// 苹果工厂
type AppleFactory struct{}

func (af *AppleFactory) CreatePhone() Phone {
    return &IPhone{}
}

func (af *AppleFactory) CreateComputer() Computer {
    return &MacBook{}
}

// 使用示例
func main() {
    factory := &HuaweiFactory{}
    phone := factory.CreatePhone()
    computer := factory.CreateComputer()
    println(phone.Call(), computer.Work()) // 输出:Huawei phone calling Huawei computer working
}

原型模式

原型模式(Prototype Pattern)是一种创建型设计模式,其核心思想是通过复制现有对象(原型)来生成新对象,而非通过传统的类实例化方式(如new关键字)。

原型模式通过克隆机制创建对象,允许一个对象作为原型,基于其生成新实例。这种方式避免了重复初始化带来的性能损耗,尤其当对象包含复杂数据结构或依赖外部资源时。

原型模式的实现有两种:

  • 浅拷贝:仅复制对象的基本类型属性和引用地址,不复制引用指向的实际对象。所有克隆对象共享同一引用成员。
  • 深拷贝:递归复制所有引用类型成员,确保克隆对象与原对象完全独立。

适配器模式

适配器模式用于解决接口不兼容的问题,通过将一个类的接口转换成客户端期望的另一个接口,使得原本不兼容的类可以协同工作。

适配器模式由三部分组成:

  • 目标接口
  • 被适配者(Adaptee)
  • 适配器

适配器模式适合应用于整合旧系统、第三方库兼容等场景,能提高代码复用性。

类适配器

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package main

import "fmt"

// --- 目标接口 ---
type USB interface {
    Connect()
}

// --- 被适配者 ---
type TypeC struct{}

func (t *TypeC) TypeCConnect() {
    fmt.Println("TypeC connected.")
}

// --- 适配器(对象适配器,通过组合实现)---
type TypeCToUSBAdapter struct {
    typeC *TypeC
}

func NewTypeCToUSBAdapter(typeC *TypeC) *TypeCToUSBAdapter {
    return &TypeCToUSBAdapter{typeC: typeC}
}

func (a *TypeCToUSBAdapter) Connect() {
    a.typeC.TypeCConnect() // 调用被适配者的方法
}

// 使用示例
func main() {
    typeC := &TypeC{}
    usbAdapter := NewTypeCToUSBAdapter(typeC)
    usbAdapter.Connect() // 输出: TypeC connected.
}

装饰器模式

装饰器模式通过动态地给对象添加额外的职责,提供比继承更灵活的扩展方式。

装饰器模式灵活扩展对象功能,支持运行时动态组合,且符合单一职责原则(每个装饰器只关注一个功能)。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
package main

import "fmt"

// --- 组件接口 ---
type Coffee interface {
    Cost() float64
    Description() string
}

// --- 具体组件 ---
type BlackCoffee struct{}

func (b *BlackCoffee) Cost() float64 {
    return 2.0
}

func (b *BlackCoffee) Description() string {
    return "Black Coffee"
}

// --- 装饰器基类(通过嵌套接口实现)---
type CoffeeDecorator struct {
    coffee Coffee
}

func (d *CoffeeDecorator) Cost() float64 {
    return d.coffee.Cost()
}

func (d *CoffeeDecorator) Description() string {
    return d.coffee.Description()
}

// --- 具体装饰器:加牛奶 ---
type MilkDecorator struct {
    CoffeeDecorator
}

func NewMilkDecorator(coffee Coffee) *MilkDecorator {
    return &MilkDecorator{CoffeeDecorator{coffee: coffee}}
}

func (m *MilkDecorator) Cost() float64 {
    return m.coffee.Cost() + 0.5
}

func (m *MilkDecorator) Description() string {
    return m.coffee.Description() + ", Milk"
}

// 使用示例
func main() {
    var coffee Coffee
    coffee = &BlackCoffee{}
    fmt.Printf("Cost: %.1f, Description: %s\n", coffee.Cost(), coffee.Description())
    // 输出: Cost: 2.0, Description: Black Coffee

    coffee = NewMilkDecorator(coffee)
    fmt.Printf("Cost: %.1f, Description: %s\n", coffee.Cost(), coffee.Description())
    // 输出: Cost: 2.5, Description: Black Coffee, Milk
}

代理模式

代理模式是一种结构型设计模式,通过引入一个代理对象来控制对真实对象的访问,实现功能增强或访问控制。其核心在于解耦客户端与真实对象,代理对象与真实对象实现相同接口,客户端通过代理间接操作真实对象。

代理模式的结构如下:

  • 抽象主题:定义代理和真实对象的公共接口(如图片加载接口)。
  • 真实主题:实际执行业务逻辑的类。
  • 代理:实现相同接口,控制对真实对象的访问(如权限检查、延迟加载)。
  • 客户端。

使用代理模式可以使代码职责清晰、扩展性强(如新增日志功能无需修改真实对象)、保护真实对象,缺陷就是可能增加类数量(静态代理)、动态代理需反射机制可能影响性能。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package main
import "fmt"

// 接口定义
type Vehicle interface { Drive() }

// 真实对象
type Car struct{}
func (c *Car) Drive() { fmt.Println("Car is being driven") }

// 代理对象
type CarProxy struct {
    vehicle Vehicle
    driver  *Driver
}

type Driver struct{ Age int }

func NewCarProxy(driver *Driver) *CarProxy {
    return &CarProxy{&Car{}, driver}
}

func (p *CarProxy) Drive() {
    if p.driver.Age >= 16 {
        p.vehicle.Drive()
    } else {
        fmt.Println("Driver too young!")
    }
}

// 客户端
func main() {
    proxy := NewCarProxy(&Driver{12})
    proxy.Drive() // 输出: Driver too young!
    
    proxy = NewCarProxy(&Driver{22})
    proxy.Drive() // 输出: Car is being driven
}

策略模式

策略模式是一种行为型设计模式,将一组算法封装为独立策略类,使客户端能动态切换算法。其核心是通过组合而非继承实现行为的灵活扩展。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package main
import "fmt"

// 策略接口
type PricingStrategy interface { CalculatePrice(float64) float64 }

// 具体策略
type RegularStrategy struct{}
func (s *RegularStrategy) CalculatePrice(p float64) float64 { return p }

type VIPStrategy struct{}
func (s *VIPStrategy) CalculatePrice(p float64) float64 { return p * 0.9 }

// 上下文
type PricingService struct{ strategy PricingStrategy }
func (s *PricingService) SetStrategy(strategy PricingStrategy) { s.strategy = strategy }
func (s *PricingService) Calculate(p float64) float64 { return s.strategy.CalculatePrice(p) }

// 客户端
func main() {
    service := &PricingService{}
    
    service.SetStrategy(&RegularStrategy{})
    fmt.Println(service.Calculate(100)) // 输出: 100
    
    service.SetStrategy(&VIPStrategy{})
    fmt.Println(service.Calculate(100)) // 输出: 90
}

命令模式

命令模式是一种行为型设计模式,将请求封装为对象,支持请求的排队、撤销和日志记录。核心在于解耦请求发送者与接收者,通过命令对象统一管理操作。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package main
import "fmt"

// 命令接口
type Command interface{ Execute() }

// 具体命令
type TVOnCommand struct{ tv *TV }
func (c *TVOnCommand) Execute() { c.tv.On() }

type TVOffCommand struct{ tv *TV }
func (c *TVOffCommand) Execute() { c.tv.Off() }

// 接收者
type TV struct{}
func (t *TV) On()  { fmt.Println("TV on") }
func (t *TV) Off() { fmt.Println("TV off") }

// 调用者
type RemoteControl struct{ cmd Command }
func (r *RemoteControl) SetCommand(cmd Command) { r.cmd = cmd }
func (r *RemoteControl) Press()                 { r.cmd.Execute() }

// 客户端
func main() {
    tv := &TV{}
    remote := &RemoteControl{}
    
    remote.SetCommand(&TVOnCommand{tv})
    remote.Press() // 输出: TV on
    
    remote.SetCommand(&TVOffCommand{tv})
    remote.Press() // 输出: TV off
}