原型模式
原型模式是一种创建型设计模式, 使你能够复制已有对象, 而又无需使代码依赖它们所属的类。
模型说明
- 原型(Prototype)接口将对克隆方法进行声明。在绝大多数情况下,其中只会有一个名为clone克隆的方法。
- 具体原型(Concrete Prototype)类将实现克隆方法。除了将原始对象的数据复制到克隆体中之外,该方法有时还需处理克隆过程中的极端情况,例如克隆关联对象和梳理递归依赖等等。
- 客户端(Client)可以复制实现了原型接口的任何对象。
优缺点
1.优点
- 你可以克隆对象,而无需与它们所属的具体类相耦合。
- 你可以克隆预生成原型,避免反复运行初始化代码。
- 你可以更方便地生成复杂对象。
- 你可以用继承以外的方式来处理复杂对象的不同配置。
2.缺点
- 克隆包含循环引用的复杂对象可能会非常麻烦。
使用场景
- 如果你需要复制一些对象,同时又希望代码独立于这些对象所属的具体类,可以使用原型模式。
- 如果子类的区别仅在于其对象的初始化方式,那么你可以使用该模式来减少子类的数量。别人创建这些子类的目的可能是为了创建特定类型的对象。
参考代码
通过基于操作系统文件系统的示例来理解原型模式。操作系统的文件系统是递归的:文件夹中包含文件和文件夹,其中又包含文件和文件夹,以此类推。
inode.go: 原型接口
go
package main
type Inode interface {
print(string)
clone() Inode
}
file.go: 具体原型
go
package main
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: 具体原型
go
package main
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
}
main.go: 客户端代码
go
package main
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(" ")
}
output:
go
Printing hierarchy for Folder2
Folder2
Folder1
File1
File2
File3
Printing hierarchy for clone Folder
Folder2_clone
Folder1_clone
File1_clone
File2_clone
File3_clone