开发过程中的设计模式

函数选项模式

用于构建灵活且可扩展的功能配置

实现方式

  1. 定义一个选项类型:可以使用接口、函数类型或结构体来定义选项。
  2. 定义一个配置函数:对于每个选项,定义一个配置函数,该函数接受目标配置结构体的指针,并修改其中的配置。
  3. 在主函数中应用选项:在需要的地方,接受这些配置函数,并将其应用于默认配置。

示例

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
// Config 是一个配置结构体
type Config struct {
Host string
Port int
TLS bool
Timeout int
}

// Option 是一个函数类型,用于配置 Config
type Option func(*Config)

// WithHost 设置主机名选项
func WithHost(host string) Option {
return func(c *Config) {
c.Host = host
}
}

// WithPort 设置端口号选项
func WithPort(port int) Option {
return func(c *Config) {
c.Port = port
}
}

// NewConfig 创建一个默认配置并应用选项
func NewConfig(options ...Option) *Config {
config := &Config{
Host: "localhost",
Port: 8080,
TLS: false,
Timeout: 30,
}

for _, option := range options {
option(config)
}

return config
}

注册表模式 + 依赖注入模式

注册表模式使用场景

  1. 存储和管理系统的配置。
  2. 跨不同组件共享单例实例。
  3. 动态加载类或框架组件。

注册表示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 服务接口
type Service interface {
Execute()
}

type Registry struct {
mu sync.RWMutex
services map[string]Service
}

// 注册和获取服务的方法保持不变,只需将 Lock/Unlock 替换为 RLock/RUnlock 和 Lock/Unlock
func (r *Registry) Register(name string, service Service) {
r.mu.Lock() // 加锁
defer r.mu.Unlock() // 解锁
r.services[name] = service
}

func (r *Registry) Get(name string) Service {
r.mu.RLock() // 读取锁
defer r.mu.RUnlock() // 读取解锁
return r.services[name]
}

依赖注入

将对象的依赖关系从内部管理转移到外部,从而使得对象的创建与其所依赖的对象解耦。

两种模式如何结合?

可将Service interface改成函数定义,示例:

1
type Service func(provider string) error