面试题答案
一键面试整体设计思路
- 单例模式:使用
sync.Once
确保全局配置对象只有一个实例,这样可以避免重复创建配置对象带来的资源浪费和不一致性问题。 - 观察者模式:用于实现配置动态更新。当配置发生变化时,通知所有关注该配置的观察者(可能是依赖这些配置的其他模块),让它们做出相应的调整。
关键代码片段
package main
import (
"fmt"
"sync"
)
// Config 代表全局配置
type Config struct {
// 假设这里有实际的配置字段,比如数据库连接字符串等
DatabaseURL string
// 其他配置字段...
}
// ConfigManager 配置管理器
type ConfigManager struct {
config *Config
observers []func()
once sync.Once
}
// GetInstance 获取单例实例
func (cm *ConfigManager) GetInstance() *Config {
cm.once.Do(func() {
cm.config = &Config{
DatabaseURL: "default-url",
// 初始化其他配置字段
}
})
return cm.config
}
// RegisterObserver 注册观察者
func (cm *ConfigManager) RegisterObserver(f func()) {
cm.observers = append(cm.observers, f)
}
// UpdateConfig 更新配置并通知观察者
func (cm *ConfigManager) UpdateConfig(newConfig *Config) {
cm.config = newConfig
for _, observer := range cm.observers {
observer()
}
}
使用示例
func main() {
configManager := &ConfigManager{}
// 获取配置实例
config1 := configManager.GetInstance()
fmt.Println("Config1:", config1.DatabaseURL)
// 注册观察者
configManager.RegisterObserver(func() {
fmt.Println("Config has been updated, taking appropriate actions...")
})
// 更新配置
newConfig := &Config{
DatabaseURL: "new-url",
}
configManager.UpdateConfig(newConfig)
// 获取更新后的配置实例
config2 := configManager.GetInstance()
fmt.Println("Config2:", config2.DatabaseURL)
}
在上述代码中:
Config
结构体定义了全局配置的结构。ConfigManager
结构体通过sync.Once
实现单例模式,并维护一个观察者列表。GetInstance
方法保证Config
实例的唯一性。RegisterObserver
方法用于注册观察者函数。UpdateConfig
方法更新配置并通知所有观察者。
通过这种方式,实现了单例模式与观察者模式的结合,满足微服务架构中全局配置单例管理且支持动态更新的需求。