设计模式-07-原型模式

原型模式是一种创建型设计模式, 使你能够复制已有对象, 而又无需使代码依赖它们所属的类(亦称: 克隆、Clone、Prototype)

如果你有一个对象, 并希望生成与其完全相同的一个复制品, 你该如何实现呢? 首先, 你必须新建一个属于相同类的对象。 然后, 你必须遍历原始对象的所有成员变量, 并将成员变量值复制到新对象中。

可能存在的问题

  1. 并非所有对象都能通过这种方式进行复制, 因为有些对象可能拥有私有成员变量, 它们在对象本身以外是不可见的
  2. 有时只知道对象所实现的接口, 而不知道其所属的具体类, 比如可向方法的某个参数传入实现了某个接口的任何对象

逻辑结构

Prototype

代码实现

代码路径:https://github.com/XBoom/DesignPatterns/tree/main/06_Prototype

  1. 具体需要被复制的对象

    1
    2
    3
    4
    5
    // ConcretePrototype 是具体原型结构体
    type ConcretePrototype struct {
    part1 string
    part2 int
    }
  2. 定义复制接口

    1
    2
    3
    4
    // Prototype 是原型接口
    type Prototype interface {
    Clone() Prototype
    }
  3. 实现复制

    1
    2
    3
    4
    5
    // Clone 是克隆方法(深拷贝)
    func (p *ConcretePrototype) Clone() Prototype {
    clone := *p //值拷贝
    return &clone
    }

这是因为 clone := *p 是值拷贝,这个地方容易忽略!!!,值拷贝,那么改成下面也可以

1
2
3
func (p ConcretePrototype) Clone() Prototype {
return &p
}

单元测试

1
2
3
4
5
6
7
8
9
10
11
12
13
func TestConcretePrototype_Clone(t *testing.T) {
prototype := &ConcretePrototype{
part1: "hello",
part2: 0,
}
clone1 := prototype.Clone()
prototype.part1 = "world"
prototype.part2 = 100
clone2 := prototype.Clone()
fmt.Printf("p1 %p %+v \n", &prototype, prototype)
fmt.Printf("p2 %p %+v \n", &clone1, clone1)
fmt.Printf("p3 %p %+v \n", &clone2, clone2)
}

输出结果为

1
2
3
p1 0xc0000a6048 &{part1:world part2:100} 
p2 0xc00008e260 &{part1:hello part2:0}
p3 0xc00008e270 &{part1:world part2:100}

总结

  1. 另外还可以通过序列号与反序列化实现深拷贝,不过需要考虑到序列化性能
  2. 考虑使用内存池进行对象创建
  3. 适用场景
    • 创建对象的过程比较复杂,需要进行多项初始化配置才能完成。
    • 需要创建大量相似或相同的对象,并且每个对象都有不同的状态和属性。
    • 由于某些原因,无法或不方便使用其他创建模式(如工厂方法模式、建造者模式等)来创建对象。
    • 希望在运行时动态地生成新对象,并且能够通过克隆来获得更好的性能

参考文档

  1. https://lailin.xyz/post/factory.html
  2. https://github.com/senghoo/golang-design-pattern