场景
当对象的创建成本比较大,并且同一个类的不同对象间差别不大时(大部分属性值相同),如果对象的属性值需要经过复杂的计算、排序,或者需要从网络、DB等这些慢IO中获取、亦或者或者属性值拥有很深的层级,这时就是原型模式发挥作用的地方了。
深拷贝,浅拷贝
// Keyword 搜索关键字
type Keyword struct {
word string
visit int
UpdatedAt *time.Time
}
// Clone 这里使用序列化与反序列化的方式深拷贝
func (k *Keyword) Clone() *Keyword {
var newKeyword Keyword
b, _ := json.Marshal(k)
json.Unmarshal(b, &newKeyword)
return &newKeyword
}
// Keywords 关键字 map
type Keywords map[string]*Keyword
// Clone 复制一个新的 keywords
// updatedWords: 需要更新的关键词列表,由于从数据库中获取数据常常是数组的方式
func (words Keywords) Clone(updatedWords []*Keyword) Keywords {
newKeywords := Keywords{}
for k, v := range words {
// 这里是浅拷贝,直接拷贝了地址
newKeywords[k] = v
}
// 替换掉需要更新的字段,这里用的是深拷贝
for _, word := range updatedWords {
newKeywords[word.word] = word.Clone()
}
return newKeywords
}
原型模式的优点
- 某些时候克隆比直接new一个对象再逐属性赋值的过程更简洁高效,比如创建层级很深的对象的时候,克隆比直接用构造会方便很多。
- 可以使用深克隆方式保存对象的状态,可辅助实现撤销操作。
原型模式的缺点
- clone方法位于类的内部,当对已有类进行改造的时候,需要修改代码,违背了开闭原则。
- 当实现深克隆时,需要编写较为复杂的代码,尤其当对象之间存在多重嵌套引用时,为了实现深克隆,每一层对象对应的类都必须支持深克隆。因此,深克隆、浅克隆需要运用得当。