四、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
go
package _41inode
import "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
/home
json
a.json
b.json
yaml
c.yaml
d.yaml
e.txt
f.sql
/home_clone
json_clone
a.json_clone
b.json_clone
yaml_clone
c.yaml_clone
d.yaml_clone
e.txt_clone
f.sql_clone
--- PASS: TestInode (0.00s)
PASS
4.1.2 inode
go
package _41inode
// inode 是文件系统的节点
type inode interface {
// 打印此节点的信息, indent 是缩进符(如\t)
print(indent string)
// 复制此节点
clone() inode
}
const printIndent = " "
4.1.3 file
go
package _41inode
import "fmt"
type file struct {
// 文件名
name string
}
func (f *file) print(indent string) {
str := indent + f.name
fmt.Println(str)
}
func (f *file) clone() inode {
return &file{name: f.name + "_clone"}
}
4.1.4 directory
go
package _41inode
import (
"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
}