GoLang設計模式05 – 原型模式
原型模式也是一種創建型模式,它可以幫助我們優雅地創建對象的拷貝。在這種設計模式裡面,將克隆某個對象的職責交給了要被克隆的這個對象。被克隆的對象需要提供一個clone()
方法。通過這個方法可以返回該對象的拷貝。
原型模式的使用場景:
- 創建新對象的操作比較耗資源(如資料庫操作)或代價比較高時。比較起從頭創建新對象,克隆對象明顯更加可取
- 要被克隆的對象創建起來比較複雜時:比如對象克隆的過程中存在深度拷貝或分層拷貝時;又比如要被克隆的對象存在無法被直接訪問到的私有成員時。
原型模式的UML類圖:
在日常中我們遇到的包含新建、copy這些操作的場景最多的就是常規的文件系統操作了。所以接下來會以文件系統為例介紹下原型模式。
在文件系統中存在文件(file)和文件夾(folder)兩類實體。其中文件夾中又可以包含文件和子文件夾。這裡我們用一個inode
介面來表示文件和文件夾。為了表示常見的複製操作,在inode
介面中還定義了一個clone()
函數。
inode.go
type inode interface { print(string) clone() inode }
file
和 folder
兩個struct實現了inode
介面。
file.go
import "fmt" type file struct { name string } func (f *file) print(indentation string) { fmt.Println(indentation + f.name) } func (f *file) clone() inode { return &file{name: f.name + "_clone"} }
folder.go
import "fmt" type folder struct { children []inode name string } func (f *folder) print(indentation string) { fmt.Println(indentation + f.name) for _, i := range f.children { i.print(indentation + indentation) } } func (f *folder) clone() inode { cloneFolder := &folder{name: f.name + "_clone"} var tempChildren []inode for _, i := range f.children { copy := i.clone() tempChildren = append(tempChildren, copy) } cloneFolder.children = tempChildren return cloneFolder }
file
和folder
兩個struct都實現了print()
和clone()
函數,根據go語言的約定,可以認為它們都繼承了inode
介面,即可以認為它們是inode
類型了。這兩者的clone()
函數會返回其各自相關的文件或文件夾的備份。為了和原有的文件/文件夾作區分,我們在複製的對象的名稱上添加了「_clone」這樣的標記。
來看看main
函數是怎樣的,main.go:
import ( "fmt" ) func main() { file1 := &file{name: "File1"} file2 := &file{name: "File2"} file3 := &file{name: "File3"} folder1 := &folder{ children: []inode{file1}, name: "Folder1", } folder2 := &folder{ children: []inode{folder1, file2, file3}, name: "Folder2", } fmt.Println("\nPrinting hierarchy for Folder2") folder2.print(" ") cloneFolder := folder2.clone() fmt.Println("\nPrinting hierarchy for clone Folder") cloneFolder.print(" ") }
運行結果是:
Printing hierarchy for Folder2 Folder2 Folder1 File1 File2 File3 Printing hierarchy for clone Folder Folder2_clone Folder1_clone File1_clone File2_clone File3_clone
程式碼已上傳至GitHub, 地址: zhyea / go-patterns / prototype-pattern
END!