From 4155ca5c79fd3480a0f81e14fe7ae9315d8524b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E6=B4=AA=E5=AE=9D?= Date: Mon, 26 Nov 2018 17:43:45 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8E=9F=E5=9E=8B=E6=A8=A1=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- prototype-pattern/README.md | 75 +++++++++++++++++++++++++++++++++++++ prototype-pattern/main.go | 24 ++++++++++++ 2 files changed, 99 insertions(+) create mode 100644 prototype-pattern/README.md create mode 100644 prototype-pattern/main.go diff --git a/prototype-pattern/README.md b/prototype-pattern/README.md new file mode 100644 index 0000000..588a499 --- /dev/null +++ b/prototype-pattern/README.md @@ -0,0 +1,75 @@ +# 原型模式 + +> wiki:原型模式是创建型模式的一种,其特点在于通过“复制”一个已经存在的实例来返回新的实例,而不是新建实例。被复制的实例就是我们所称的“原型”,这个原型是可定制的。原型模式多用于创建复杂的或者耗时的实例,因为这种情况下,复制一个已经存在的实例使程序运行更高效;或者创建值相等,只是命名不一样的同类数据。 + +这是一个十分简单的设计模式,可以看做是其他语言中的克隆方法,例如 `JAVA`/`PHP` 中都有相关方法,从一个内存中已经存在的对象中,拷贝出一个一模一样的对象来,针对复杂对象或比较大的对象,要比使用各种设计模式`new`出来的对象要快的多, + +而且原型模式很少单独使用,一般与其他对象结合使用。 + +### 栗子 + +1. 创建一个结构体 + + ```go + // 示例结构体 + type Example struct { + Content string + } + ``` + +2. 添加克隆方法 + + ```go + func (e *Example) Clone() *Example { + res := *e + return &res + } + ``` + 我们仅仅一行代码就完成了值的拷贝,使用 `*指针`,直接获取了一个拷贝的值,然后将这个拷贝的值得指针返回,原理请阅读下面的扩展阅读。 + +3. 编写主代码 + + ```go + func main() { + r1 := new(Example) + r1.Content = "this is example 1" + r2 := r1.Clone() + r2.Content = "this is example 2" + + fmt.Println(r1) + fmt.Println(r2) + + } + ``` + + + +### 扩展阅读: 深拷贝与浅拷贝 + + `go` 语言中的传递都是值传递,传递一个对象,就会把对象拷贝一份传入函数中,传递一个指针,就会把指针拷贝一份传入进去。 + + 赋值的时候也是这样,`res:=*e` 就会把传递的 `Example` 对象拷贝一份,如果是 `res:=e` 的话,那么拷贝的就是对象的指针了. + + 而深拷贝和浅拷贝也可以这样理解,深拷贝就是拷贝整个对象,浅拷贝就是拷贝对象指针。 + + 对于深度拷贝,`go`和其他语言还经常使用序列化后反序列化的形式进行拷贝: + + ```go + func deepCopy(dst, src interface{}) error { + var buf bytes.Buffer + if err := gob.NewEncoder(&buf).Encode(src); err != nil { + return err + } + return gob.NewDecoder(bytes.NewBuffer(buf.Bytes())).Decode(dst) + } + ``` + + 实际上`gob`包序列化的时候也是用到了 `reflect`包来实现拷贝的 + + **注意:** golang完全是按值传递,所以如果深度拷贝的对象中包含有指针的话,那么深度拷贝后,这些指针也会相同,会导致部分数据共享,要注意这一点. + +至此,所有创建型的设计模式就已经全部写完了,可以去下面的仓库中找到其他的设计模式喔.... + +> 上述代码均放在 [golang-design-patterns](https://github.com/silsuer/golang-design-patterns) 这个仓库中 + +> 打个广告,推荐一下自己写的 go web框架 [bingo](https://github.com/silsuer/bingo),求star,求PR ~ \ No newline at end of file diff --git a/prototype-pattern/main.go b/prototype-pattern/main.go new file mode 100644 index 0000000..1bcbab0 --- /dev/null +++ b/prototype-pattern/main.go @@ -0,0 +1,24 @@ +package main + +import "fmt" + +// 示例结构体 +type Example struct { + Content string +} + +func (e *Example) Clone() *Example { + res := *e + return &res +} + +func main() { + r1 := new(Example) + r1.Content = "this is example 1" + r2 := r1.Clone() + r2.Content = "this is example 2" + + fmt.Println(r1) + fmt.Println(r2) + +}