Prototype Pattern(原型模式)


Clone()

注意原型模式返回的一定是新的内存实例

当直接创建对象的代价比较大时,使用这种模式。例如,一个对象需要在一个高代价的数据库操作之后被创建。我们可以缓存该对象,在下一个请求时返回它的克隆,在需要的时候更新数据库,以此来减少数据库调用。

五大要素


来看看原型模式的五大要素:

Clone()Clone()

Go实现原型模式


场景

Clone()
prototype.go
package prototype

// Cloneable接口,动物必须实现这个接口
type Cloneable interface {
	Clone() Cloneable
}

// 克隆实验室
type CloneLab struct {
	animals map[string]Cloneable
}

func NewPrototypeManager() *CloneLab {
	return &CloneLab{animals:make(map[string]Cloneable)}
}

// 获取克隆
func (p *CloneLab) Get(name string) Cloneable {
	return p.animals[name]
}

// set动物当前属性
func (p *CloneLab) Set(name string,prototype Cloneable) {
	p.animals[name] = prototype
}
prototype_test.go
package prototype

import (
	"testing"
)

var lab *Cloneable

// 羊
type Sheep struct {
	name string
	weight int
}

func (s *Sheep) Clone() Cloneable {
	tc := *s
	return &tc
}

// 牛
type Cow struct {
	name string
	gender bool
}

func (c *Cow) Clone() Cloneable  {
	newCow := &Cow{
		name:  c.name,
		gender: c.gender,
	}
	return newCow
}


func TestClone(t *testing.T) {
	sheep1 := &Sheep{
		name:   "sheep",
		weight: 10,
	}

	sheep2 := sheep1.Clone()
	
  // 这里地址肯定不同,因为是一个新的实例
	if sheep1 == sheep2 {
		t.Fail()
	}
}

func TestCloneFromManager(t *testing.T) {
	lab := NewCloneLab()

	lab.Set("cow", &Cow{name: "i am cow", gender: true})

	c := lab.Get("cow").Clone()

	cw := c.(*Cow)
	if cw.name != "i am cow" {
		t.Fatal("error")
	}
}

原型模式与工厂模式的区别

如果我们想要一个空的干净的对象,那么我们可以用工厂模式,但是当我们想获取当前动态的对象的一个拷贝实例,需要用原型模式。