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

缘起

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

原型模式

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

场景

  • 某多用户业务零碎, 提供用户自助注册的性能
  • 用户具备ID, Name, RolList(角色列表)等属性
  • 创立用户时, 须要给用户默认调配"guest" 角色
  • 用户的默认值, 应用json文件进行配置

设计

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

prototype_test.go

单元测试

package patternsimport (    "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_Prototypeu1 = &{0 新用户 [guest]}u2 = &{0 新用户 [guest]}--- PASS: Test_Prototype (0.00s)PASSok      command-line-arguments  0.002s

ICloneable.go

定义克隆接口

package prototypetype ICloneable interface {    Clone() ICloneable}

UserInfo.go

UserInfo封装了用户信息, 并实现了ICloneable接口, 能够深度克隆本身

package prototypetype 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 prototypeimport (    "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)