原型模式是一种创建型设计模式,使你能够复制已有对象,而又无需使代码依赖它们所属的类。原型模式将克隆过程委派给被克隆的实际对象。模式为所有支持克隆的对象声明了一个通用接口,该接口让你能够克隆对象,同时又无需将代码和对象所属类耦合。通常情况下,这样的接口中仅包含一个克隆方法。
解决的什么问题?
如果对象的创建成本比较大,而同一个类的不同对象之间差别不大(大部分字段都相同),在这种情况下,我们可以利用对已有对象(原型)进行复制(或者叫拷贝)的方式,来创建新对象,以达到节省创建时间的目的。
实现步骤:
-
创建原型接口, 并在其中声明
克隆方法。 -
原型类必须另行定义一个以该类对象为参数的构造函数。 构造函数必须复制参数对象中的所有成员变量值到新实体中。
-
克隆方法通常只有一行代码: 使用
new运算符调用原型版本的构造函数。 -
你还可以创建一个中心化原型注册表, 用于存储常用原型。
优点:
- 你可以克隆对象, 而无需与它们所属的具体类相耦合。
- 你可以克隆预生成原型, 避免反复运行初始化代码。
- 你可以更方便地生成复杂对象。
- 你可以用继承以外的方式来处理复杂对象的不同配置。
缺点:
- 克隆包含循环引用的复杂对象可能会非常麻烦。
下面是具体代码实现示例:
package main
import "fmt"
type prototype interface {
clone() house
}
type house struct {
name string
wall string
pool bool
tree bool
}
func (h *house) show() {
fmt.Printf("name: %s, wall: %s, pool: %v, tree: %v\n", h.name, h.wall, h.pool, h.tree)
}
func (h *house) clone() *house {
n := *h
return &n
}
type prototypeRegistry struct {
items map[string]*house
}
func (p *prototypeRegistry) getByName(name string) *house {
house, ok := p.items[name]
if !ok {
return nil
}
return house.clone()
}
var registry = prototypeRegistry{
items: map[string]*house{
"woodHouseWithPool": &house {
name: "woodHouseWithPool",
wall: "wood",
pool: true,
tree: false,
},
"woodHouseWithTree": &house {
name: "woodHouseWithTree",
wall: "wood",
pool: false,
tree: true,
},
},
}
func main() {
house := registry.getByName("woodHouseWithPool")
house.show()
house = registry.getByName("woodHouseWithTree")
house.show()
}