Skip to main content
 首页 » 编程设计

使用go实现原型模式

2022年07月19日140exmyth

原型模式

定义

如果对象的创建成本比较大,而同一个类的不同对象之间差别不大(大部分字段都相同),在这种情况下,我们可以利用对已有对象(原型)进行复制(或者叫拷贝)的方式来创建新对象,以达到节省创建时间的目的。这种基于原型来创建对象的方式就叫作原型设计模式(Prototype Design Pattern),简称原型模式。

原型模式是能基于拷贝来的,对于拷贝我们知道有两种形式,深拷贝和浅拷贝

浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存。但深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。

原型模式浅拷贝:

1、省内存,拷贝时间更快;

2、浅拷贝容易出现原始数据被修改的情况,一般不建议使用;

3、浅拷贝可以拷贝不可变对象;

原型模式深拷贝:

1、数据完全隔离;

2、不过数据量大的情况下,深拷贝比起浅拷贝来说,更加耗时,更加耗内存空间;

代码实现

// Cloneable 是原型对象需要实现的接口 
type Cloneable interface { 
	Clone() Cloneable 
} 
 
type PrototypeManager struct { 
	prototypes map[string]Cloneable 
} 
 
func NewPrototypeManager() *PrototypeManager { 
	return &PrototypeManager{ 
		prototypes: make(map[string]Cloneable), 
	} 
} 
 
func (p *PrototypeManager) Get(name string) Cloneable { 
	return p.prototypes[name].Clone() 
} 
 
func (p *PrototypeManager) Set(name string, prototype Cloneable) { 
	p.prototypes[name] = prototype 
} 

测试文件

var ( 
	deepCopyManager    *PrototypeManager 
	shallowCopyManager *PrototypeManager 
) 
 
// 深拷贝实现Cloneable 
type DeepCopy struct { 
	name string 
} 
 
func (t *DeepCopy) Clone() Cloneable { 
	tc := *t 
	return &tc 
} 
 
// 浅拷贝实现Cloneable 
type ShallowCopy struct { 
	name string 
} 
 
func (t *ShallowCopy) Clone() Cloneable { 
	return t 
} 
 
func TestDeepCopyClone(t *testing.T) { 
	t1 := deepCopyManager.Get("dc") 
 
	t2 := t1.Clone() 
	// 深拷贝,指向的不是同一个变量的地址 
	if t1 == t2 { 
		t.Fatal("error! get clone not working") 
	} 
 
	t21 := t2.(*DeepCopy) 
	t21.name = "ShallowCopy-test" 
 
	t11 := t1.(*DeepCopy) 
	// 深拷贝name,不会影响到copy前的变量 
	if t11.name == t21.name { 
		t.Fatal("shallowCopy err") 
	} 
} 
 
func TestShallowCopyClone(t *testing.T) { 
	t1 := shallowCopyManager.Get("sc") 
 
	t2 := t1.Clone() 
	// 浅拷贝,变量地址的指向不变 
	if t1 != t2 { 
		t.Fatal("error! get clone not working") 
	} 
 
	t21 := t2.(*ShallowCopy) 
	t21.name = "ShallowCopy-test" 
 
	t11 := t1.(*ShallowCopy) 
	// 深拷贝name,copy之前的变量和copy之后的变量同时更改 
	if t11.name != t21.name { 
		t.Fatal("shallowCopy err") 
	} 
} 
 
func init() { 
	deepCopyManager = NewPrototypeManager() 
 
	dc := &DeepCopy{ 
		name: "deepCopy", 
	} 
	deepCopyManager.Set("dc", dc) 
 
	shallowCopyManager = NewPrototypeManager() 
	sc := &ShallowCopy{ 
		name: "shallowCopy", 
	} 
	shallowCopyManager.Set("sc", sc) 
} 

优点

1、使用原型模式创建对象比直接new一个对象在性能上要好的多,因为是直接进行的内存拷贝,比初始化性能上会好很多;

2、简化对象的创建,对于创建对象就像我们在编辑文档时的复制粘贴一样简单。

缺点

克隆包含循环引用的复杂对象可能会非常麻烦。

适用场景

1、在项目中,如果存在大量相同或相似对象的创建,如果用传统的构造函数来创建对象,会比较复杂和耗费资源,用原型模式生产对象就很高效;

2、对象创建过程比较麻烦,但复制比较简单的时候;

参考

【文中代码】https://github.com/boilingfrog/design-pattern-learning/tree/master/原型模式
【大话设计模式】https://book.douban.com/subject/2334288/
【极客时间】https://time.geekbang.org/column/intro/100039001
【原型模式】https://github.com/senghoo/golang-design-pattern
【原文地址】https://boilingfrog.github.io/2021/11/08/使用go实现原型模式/


本文参考链接:https://www.cnblogs.com/ricklz/p/15525612.html
阅读延展