Prototype 原型模式其实就是根据实例的原型生成新的实例的一种创建型设计模式。使你能够复制对象, 甚至是复杂对象, 而又无需使代码依赖它们所属的类。
典型的应用就是依赖注入,做过.Net 和 Java开发的小伙伴应该对此很熟悉。go也有依赖注入框架

场景

本期场景就很简单了,我们实现了一个简单的依赖注入模型。

基础类型和接口

这是原型接口,需要实现依赖注入的实例必须实现这个接口

// 产品接口(原型接口)
type Product interface {
    // 用于演示的方法
    Use()
    // 克隆方法,返回自身的副本(不是指针)
    Clone() Product
}

原型池管理
Manager内部有一个Map,Map内保存的是已经注册的实例,提供注册Register()以及获取原型的实例的方法Clone()

// 产品管理
type Manager struct {
    // 原型池
    products map[string]Product
}

// 注册原型到原型池
func (m *Manager) Register(name string, product Product) {
    _, ok := m.products[name]
    if ok {
        return
    }

    m.products[name] = product
}

// Clone一个对象,返回其副本
func (m *Manager) Clone(name string) Product {
    v, ok := m.products[name]
    if !ok {
        return nil
    }

    // 调用被克隆对象自身的克隆方法
    return v.Clone()
}

实现

定义了一个实现了原型接口的IPhone类型

// 演示产品,实现了原型接口
type IPhone struct {
    Name string
}

// 演示方法
func (p *IPhone) Use() {
    fmt.Printf("正在使用 %s 打电话\n", p.Name)
}

// 克隆的细节
func (p *IPhone) Clone() Product {
    return &IPhone{Name: p.Name + "_clone"}
}

测试

这边我通过输出对象指针来判断Clone()返回的不是原型自身

func main() {
    iphone7 := IPhone{Name: "IPhone7"}
    iphone7.Use()
    fmt.Printf("%s 的指针式 %p \n\n", iphone7.Name, &iphone7)

    manager := Manager{products: make(map[string]Product)}
    manager.Register("iphone7", &iphone7)

    clone_iphone7 := manager.Clone("iphone7")
    clone_iphone7.Use()
    fmt.Printf("clone_iphone7 的指针式 %p \n", &clone_iphone7)
}

运行结果
描述

结果符合预期

 代码已上传Github:LyonNee/design_patterns_with_go: 基于Golang实现的设计模式代码 (github.com)