设计模式5:原型模式

主要思想:如果你有一个对象,并且你想创建一个完全相同的副本,你可以创建一个新的实例然后手动设置它的值,但这样做有一个问题,你需要知道对象的内部结构和属性。更好的方式是让原来的对象自己完成这个复制过程,这就是原型模式的主要目的。

意图:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

主要解决:在运行期建立和删除原型。

何时使用: 1、当一个系统应该独立于它的产品创建,构成和表示时。 2、当要实例化的类是在运行时刻指定时,例如,通过动态装载。 3、为了避免创建一个与产品类层次平行的工厂类层次时。 4、当一个类的实例只能有几个不同状态组合中的一种时。建立相应数目的原型并克隆它们可能比每次用合适的状态手工实例化该类更方便一些。

示例

type Sheep struct {
	Name     string
	Category string
}

func (s *Sheep) Clone() *Sheep {
	return &Sheep{
		Name:     s.Name,
		Category: s.Category,
	}
}

func main() {
	original := &Sheep{
		Name:     "Jolly",
		Category: "Mountain Sheep",
	}
	fmt.Println(original)

	clone := original.Clone()
	fmt.Println(clone)
}

在 go 中的应用

原型模式在 Go 语言的开源项目中并不常见,因为 Go 语言的设计哲学倾向于简洁和明确。在许多情况下,Go 语言的开发者更倾向于使用更直接的方式来创建对象,而不是使用设计模式。但是,我们仍然可以在一些项目中找到原型模式的影子。

Go 语言标准库中的 net/http 包:在 http 包中,Request 结构体有一个 Clone 方法,可以创建一个新的 Request 实例并复制原有实例的值。这实际上是原型模式的一种实现。这个 Clone 方法在处理 HTTP 请求时非常有用,例如,我们可以创建一个原始请求的副本,然后修改副本的某些属性,而不影响原始请求。
go

func (r *Request) Clone(ctx context.Context) *Request

Kubernetes:在 Kubernetes 的源码中,有一些地方用到了类似原型模式的设计。比如在 API 对象的深度复制中,每个 API 对象都有一个 DeepCopy 方法,这个方法会返回一个新的对象,并且复制了原对象的所有值。这个 DeepCopy 方法的实现是通过代码生成器自动生成的,这种方式虽然和传统的原型模式有所不同,但是本质上是一样的,都是创建一个新的对象并复制原对象的值。

func (in *Pod) DeepCopy() *Pod {
	if in == nil {
		return nil
	}
	out := new(Pod)
	in.DeepCopyInto(out)
	return out
}