四、prototype 原型模式
https://refactoringguru.cn/design-patterns/prototype
如果希望 复制对象, 可使用 “prototype 模式”
如果 “待复制的对象” 是 interface 而不是 class, 或者如果 class 有 private 变量时. 无法知道 "待复制的对象"的细节, 则需要其实现 “clone()” 方法供外部调用.
4.1 inode
本例希望实现文件系统的复制功能. 数据结构是 inode 接口, file 和 folder 都实现了该接口. 详见 https://refactoringguru.cn/design-patterns/prototype/go/example
当然, 另一条路是: 也可以直接用序列化+反序列化实现复杂对象的 clone()
4.1.1 inode_test
package _41inodeimport "testing"func TestInode(t *testing.T) {d1 := &directory{name: "json",children: []inode{&file{name: "a.json"}, &file{name: "b.json"}},}d2 := &directory{name: "yaml",children: []inode{&file{"c.yaml"}, &file{"d.yaml"}},}f1 := &file{name: "e.txt"}f2 := &file{name: "f.sql"}directoryHome := directory{name: "/home",children: []inode{d1, d2, f1, f2},}directoryHome.print(printIndent)cp := directoryHome.clone()cp.print(" ")
}// code result
=== RUN TestInode/homejsona.jsonb.jsonyamlc.yamld.yamle.txtf.sql/home_clonejson_clonea.json_cloneb.json_cloneyaml_clonec.yaml_cloned.yaml_clonee.txt_clonef.sql_clone
--- PASS: TestInode (0.00s)
PASS
4.1.2 inode
package _41inode// inode 是文件系统的节点
type inode interface {// 打印此节点的信息, indent 是缩进符(如\t)print(indent string)// 复制此节点clone() inode
}const printIndent = " "
4.1.3 file
package _41inodeimport "fmt"type file struct {// 文件名name string
}func (f *file) print(indent string) {str := indent + f.namefmt.Println(str)
}func (f *file) clone() inode {return &file{name: f.name + "_clone"}
}
4.1.4 directory
package _41inodeimport ("fmt"
)type directory struct {// 目录名name string// 子节点children []inode
}func (d *directory) print(indent string) {fmt.Println(indent + d.name)for _, child := range d.children {child.print(indent + printIndent) // 在基础 indent 的基础上, 再添加 printIndent}
}func (d *directory) clone() inode {children := make([]inode, 0)for _, child := range d.children {children = append(children, child.clone())}cp := &directory{name: d.name + "_clone",children: children,}return cp
}