【设计模式】4、prototype 原型模式

四、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 _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

package _41inode

// inode 是文件系统的节点
type inode interface {
	// 打印此节点的信息, indent 是缩进符(如\t)
	print(indent string)
	// 复制此节点
	clone() inode
}

const printIndent = "  "

4.1.3 file

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

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
}

上一篇:Golang实践:用Sync.Map实现简易内存缓存系统-介绍


下一篇:[神坑已解决]Http请求参数中的加号被转换为空格的问题