美文网首页设计模式
手撸golang 创建型设计模式 原型模式

手撸golang 创建型设计模式 原型模式

作者: 老罗话编程 | 来源:发表于2021-01-31 20:36 被阅读0次

    手撸golang 创建型设计模式 原型模式

    缘起

    最近复习设计模式
    拜读谭勇德的<<设计模式就该这样学>>
    本系列笔记拟采用golang练习之

    原型模式

    原型模式(Prototype Pattern)指原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象,属于创建型设计模式。
    _

    场景

    • 某多用户业务系统, 提供用户自助注册的功能
    • 用户具有ID, Name, RolList(角色列表)等属性
    • 创建用户时, 需要给用户默认分配"guest" 角色
    • 用户的默认值, 使用json文件进行配置

    设计

    • 定义UserInfo类, 表示用户信息
    • UserInfo类实现了ICloneable接口, 可以深度克隆自身
    • 定义UserFactory类, 作为创建新用户的简单工厂
    • 初始化UserFactory时, 从磁盘加载默认用户的属性配置, 并创建一个UserInfo实例, 作为用户信息的原型
    • 创建新用户时, 调用原型用户的Clone()方法, 复制副本并返回

    prototype_test.go

    单元测试

    package patterns
    
    import (
        "fmt"
        pt "learning/gooop/creational_patterns/prototype"
        "testing"
    )
    
    func Test_Prototype(t *testing.T) {
        u1 := pt.DefaultUserFactory.Create()
        fmt.Printf("u1 = %v\n", u1)
    
        u2 := pt.DefaultUserFactory.Create()
        fmt.Printf("u2 = %v\n", u2)
    }
    

    测试输出

    $ go test -v prototype_test.go 
    === RUN   Test_Prototype
    u1 = &{0 新用户 [guest]}
    u2 = &{0 新用户 [guest]}
    --- PASS: Test_Prototype (0.00s)
    PASS
    ok      command-line-arguments  0.002s
    
    

    ICloneable.go

    定义克隆接口

    package prototype
    
    type ICloneable interface {
        Clone() ICloneable
    }
    

    UserInfo.go

    UserInfo封装了用户信息, 并实现了ICloneable接口, 可以深度克隆自身

    package prototype
    
    type UserInfo struct {
        ID int
        Name string
        RoleList []string
    }
    
    func newEmptyUser() *UserInfo {
        return &UserInfo{}
    }
    
    func (me *UserInfo) Clone() ICloneable {
        roles := me.RoleList
        it := &UserInfo{
            me.ID, me.Name, make([]string, len(roles)),
        }
    
        for i,s := range roles {
            it.RoleList[i] = s
        }
        return it
    }
    

    UserFactory.go

    UserFactory实现了创建UserInfo的简单工厂.
    创建的过程本质是调用了用户原型的Clone方法.
    用户原型是从json配置加载的, 便于按需修改配置.

    package prototype
    
    import (
        "encoding/json"
        "strings"
    )
    
    // 用户工厂的全局单例
    var DefaultUserFactory IUserFactory = newUserFactory()
    
    type IUserFactory interface {
        Create() *UserInfo
    }
    
    type tUserFactory struct {
        defaultUserInfo *UserInfo
    }
    
    // 创建用户工厂实例
    func newUserFactory() *tUserFactory {
        reader := strings.NewReader(loadUserConfig())
        decoder := json.NewDecoder(reader)
        user := newEmptyUser()
        e := decoder.Decode(user)
        if e != nil {
            panic(e)
        }
    
        return &tUserFactory{
            defaultUserInfo: user,
        }
    }
    
    // 加载默认用户的属性配置
    func loadUserConfig() string {
        return `{
        "ID": 0,
        "Name" : "新用户",
        "RoleList" : ["guest"]
    }`
    }
    
    
    func (me *tUserFactory) Create() *UserInfo {
        return me.defaultUserInfo.Clone().(*UserInfo)
    }
    

    原型模式小结

    原型模式的优点
    (1) 某些时候克隆比直接new一个对象再逐属性赋值的过程更简洁高效。
    (2)可以使用深克隆方式保存对象的状态,可辅助实现撤销操作。
    原型模式的缺点
    (1)需要配置一个clone方法。
    (2)clone方法位于类的内部,当对已有类进行改造的时候,需要修改代码,违背了开闭原则。
    (3)当实现深克隆时,需要编写较为复杂的代码,尤其当对象之间存在多重嵌套引用时,为了实现深克隆,每一层对象对应的类都必须支持深克隆。因此,深克隆、浅克隆需要运用得当。

    (end)

    相关文章

      网友评论

        本文标题:手撸golang 创建型设计模式 原型模式

        本文链接:https://www.haomeiwen.com/subject/erzrtltx.html