5. Режим прототипа
Режим прототипа, использующий экземпляры прототипа для указания типов создаваемых объектов и создания новых объектов путем копирования этих объектов-прототипов.
Например, есть резюме, в котором часть личной информации должна быть одинаковой, поэтому мы можем использовать ее в качестве прототипа, а затем сгенерировать новый экземпляр с помощью метода Clone () прототипа, изменить уникальную информацию в новом экземпляре для достижения нашего цель. Кроме того, модификации разных примеров не должны мешать друг другу . Конкретные операции заключаются в следующем:
prototype\
Создайте новый файл под путем , prototype.go
и имя пакета prototype
:
package prototype
// ...
Предполагается, что резюме будет содержать такую информацию, как имя, пол, школа, компания, подающая заявку, заявление о приеме на работу и т. Д. Здесь мы используем структуру для хранения информации о школе:
type School struct {
Name string
Address string
Level string
}
// 创建School实例,返回对应指针
func NewSchool(name, address, level string) *School {
return &School{
Name: name,
Address: address,
Level: level,
}
}
Мы используем прототипный метод Clone () для копирования нового экземпляра, поэтому, чтобы разные экземпляры не мешали друг другу, мы должны использовать глубокое копирование. School также необходимо реализовать метод Clone (), поэтому прототип предназначен для School () При клонировании вызывается школьный метод Clone ().
// School也要实现Clone()方法
func (s *School) Clone() *School {
return NewSchool(s.Name, s.Address, s.Level)
}
// 重写School的String()方法,便于输出信息
func (s *School) String() string {
return "{" + s.Name + " " + s.Address + " " + s.Level + "}"
}
Затем есть структура Resume и соответствующий новый метод экземпляра Resume:
Здесь следует отметить, что структура в Go является типом значения, а не типом указателя.При создании новой составной структуры значение структуры будет скопировано в прошлом, поэтому здесь используются указатели School. Кроме того, можно сэкономить определенное количество места.
type Resume struct {
Name string
Gender string
// 由于Go中结构体是值类型而不是指针类型,创建新的复合结构体时,会把值复制一份过去,所以这里使用School指针
School *School
Apply4Company string
Apply4Job string
}
func NewResume(name, gender string, school *School, company, job string) *Resume {
return &Resume{
Name: name,
Gender: gender,
School: school,
Apply4Company: company,
Apply4Job: job,
}
}
В отношении прототипа метода Clone () следует отметить, что нам нужно использовать его r.School.Clone()
для копирования r.School
(фактически указатель) и вставки в него.
// 原型的Clone()方法
func (r *Resume) Clone() *Resume {
// 注意这里的r.School.Clone()
return NewResume(r.Name, r.Gender, r.School.Clone(), r.Apply4Company, r.Apply4Job)
}
prototype
Создайте новый main.go
метод тестирования в том же каталоге пути :
package main
import (
"fmt"
"github.com/loveshes/go-design-patterns/pattern/prototype-pattern/prototype"
)
func main() {
ncu := prototype.NewSchool("南昌大学", "江西省南昌市", "211")
proto := prototype.NewResume("王英俊", "男", ncu, "", "")
// 简历一
alibaba := proto.Clone()
alibaba.Apply4Company = "Alibaba"
alibaba.Apply4Job = "Java Web"
fmt.Println("alibaba:", *alibaba)
// 简历二
bytedance := proto.Clone()
// 修改复合结构体中的School.Level字段,看alibaba中的是否也会改变
bytedance.School.Level = "双一流"
bytedance.Apply4Company = "ByteDance"
bytedance.Apply4Job = "Go"
fmt.Println("修改School.Level后,alibaba:", *alibaba)
fmt.Println("修改School.Level后,bytedance:", *bytedance)
}
Выход
alibaba: {王英俊 男 {南昌大学 江西省南昌市 211} Alibaba Java Web}
修改School.Level后,alibaba: {王英俊 男 {南昌大学 江西省南昌市 211} Alibaba Java Web}
修改School.Level后,bytedance: {王英俊 男 {南昌大学 江西省南昌市 双一流} ByteDance Go}
Видно, что изменения в School.Level в CV2 не повлияли на CV1.
Кроме того, вы можете изменить r.Clone()
средний, r.School.Clone()
чтобы r.School
увидеть, имеет ли он какой-либо эффект.
Кроме того, так как сама структура является значение типа Go, то Resume
структура *School
изменилась School
, если не используется r.School.Clone()
, по- прежнему помех между различными экземплярами.