設計模式學習-使用go實現原型模式


原型模式

定義

如果對象的創建成本比較大,而同一個類的不同對象之間差別不大(大部分字段都相同),在這種情況下,我們可以利用對已有對象(原型)進行復制(或者叫拷貝)的方式來創建新對象,以達到節省創建時間的目的。這種基於原型來創建對象的方式就叫作原型設計模式(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實現原型模式/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM