原型模式与缓存结合的核心思路
原型模式的核心是通过克隆已有原型对象来创建新对象,而缓存的作用是将已经创建好的原型对象存储起来,后续需要创建对象时直接从缓存中获取原型进行克隆,避免重复执行复杂的初始化逻辑。在Golang中,我们可以通过定义原型接口、实现具体原型结构体、维护一个原型缓存容器这三个部分来实现两者的结合。

1. 定义原型接口
首先需要定义一个原型接口,接口中需要包含克隆方法,所有需要支持原型模式的结构体都需要实现这个接口。
// Prototype 原型接口,定义克隆方法
type Prototype interface {
Clone() Prototype
SetName(name string)
GetName() string
}
2. 实现具体原型结构体
接下来实现具体的原型结构体,结构体中可以包含需要初始化的属性,同时实现原型接口的克隆方法,克隆时需要注意深拷贝和浅拷贝的问题,这里以深拷贝为例。
// ConcretePrototype 具体原型结构体
type ConcretePrototype struct {
name string
data map[string]string
}
// Clone 实现克隆方法,深拷贝数据
func (c *ConcretePrototype) Clone() Prototype {
newData := make(map[string]string)
for k, v := range c.data {
newData[k] = v
}
return &ConcretePrototype{
name: c.name,
data: newData,
}
}
func (c *ConcretePrototype) SetName(name string) {
c.name = name
}
func (c *ConcretePrototype) GetName() string {
return c.name
}
3. 实现原型缓存容器
缓存容器用来存储已经初始化好的原型对象,我们可以提供一个获取原型的方法,先从缓存中查找,如果不存在则创建并放入缓存。
// PrototypeCache 原型缓存结构体
type PrototypeCache struct {
cache map[string]Prototype
}
// NewPrototypeCache 创建缓存实例
func NewPrototypeCache() *PrototypeCache {
return &PrototypeCache{
cache: make(map[string]Prototype),
}
}
// GetPrototype 从缓存获取原型,不存在则初始化
func (p *PrototypeCache) GetPrototype(key string) Prototype {
if proto, ok := p.cache[key]; ok {
return proto.Clone()
}
// 模拟复杂初始化逻辑,这里初始化一个默认原型
newProto := &ConcretePrototype{
name: "default",
data: map[string]string{
"key1": "value1",
"key2": "value2",
},
}
p.cache[key] = newProto
return newProto.Clone()
}
完整使用示例
下面是将原型模式和缓存结合使用的完整示例,展示如何通过缓存获取原型并创建新对象。
package main
import "fmt"
// 上述定义的Prototype、ConcretePrototype、PrototypeCache相关代码放在这里
func main() {
cache := NewPrototypeCache()
// 第一次获取原型,会触发初始化并放入缓存
proto1 := cache.GetPrototype("test")
proto1.SetName("proto1")
fmt.Println("proto1 name:", proto1.GetName())
// 第二次获取原型,直接从缓存克隆,不会重复初始化
proto2 := cache.GetPrototype("test")
proto2.SetName("proto2")
fmt.Println("proto2 name:", proto2.GetName())
// 验证两个对象是独立的
fmt.Println("proto1 name after proto2 set:", proto1.GetName())
}
适用场景与注意事项
这种实现方式适合对象初始化成本较高、且需要频繁创建相似对象的场景,比如配置对象、模板对象等。需要注意克隆方法的实现要保证数据的独立性,避免修改克隆对象影响原型对象的数据,如果是包含引用类型的属性,需要实现深拷贝逻辑。另外缓存的键需要根据实际业务场景设计,确保能正确区分不同的原型类型。