开发者学堂课程【Go 语言核心编程 - 面向对象、文件、单元测试、反射、TCP 编程:工厂模式详解】学习笔记,与课程紧密联系,让用户快速学习知识。
课程地址:https://developer.aliyun.com/learning/course/626/detail/9685
工厂模式详解
内容介绍:
一、工厂模式的说明
二、工厂模式的需求
三、选择使用工厂模式实现跨包创建结构体实例(变量)的案例
四、思考题
一、工厂模式的说明
Golang 的结构体没有构造函数,通常可以使用工厂模式来解决这个问题。换言之,工厂模式就相当于是构造函数的功能。
二、工厂模式的需求
一个结构体的声明如下所示:
package model
type Student struct {
Name string...
}
因为这里的 Student 的首字母s是大写的,如果我们想在其它包创建 Student 的实例(比如 main 包),引入 model 包后,就可以直接创建 Student 结构体的变量(实例)。但是问题来了,如果首字母是小写的,比如是 type student struct {}此时就不可以在其他包进行引用,而更多情况下我们希望首字母是小写的,并且希望结构体可以在其他包中使用,这时就需要引用工厂模式来完成上述需求。
三、使用工厂模式实现跨包创建结构体实例(变量)的案例
1.如果 model 包的结构体变量首字母大写,引入后可以直接使用。
在 chapter10 中新建一个文件夹,命名为 factory ,然后再在该文件夹下创建两个文件,一个是 main 文件,一个是 model 文件。在 model 中新建一个文件student.go,在里面输入 model 包(package model),定义一个大写的结构体 Student。结构体中有两个字段,学生的姓名(Name)以及考试的成绩(score),分别是 string 类型和 float64类型。定义完成后保存,进入 main 包后引入 student 包后可以直接调用,代码为 package main import("fmt""go_code/chapter10/factory/mode1")
。然后定义一个主函数(func main()),并创建一个创建一个Student的实例(变量),代码为:var stu=mode1.Student{
,此时直接写入Name : "tom",Score :78.9,即可完成赋值,例如学生姓名为tom,他的考试成绩是78.9,调用后发现输出结果=为汤姆78.9,与理论结果一致。但是此时的问题是如果说如果student是小写,再在main包中调用时,只将main包中的相应代码改为小写,不能实现调用,而且将会报告该变量不可导出。
核心代码:
package model
//定义一个结构体
type student struct{
Name string
Score float64
}
package main
import (
"fmt"
"go_code/chapter10/factory/mode1"
)
func main(){
//创建一个 student 实例
var stu=mode1.Student{
Name : "tom",
Score :78.9,
}
fmt.Print1n(stu)
}
2.如果 model 包的结构体变量首字母小写引入后,不能直接使用,可以通过工厂模式解决
在 student.go 文件中将结构体类型进行更改,全部改成小写模式,更改之后 main 文件中的相应代码就会报错,即不能够在main文件中使用了(因为 student 结构体首字母是小写,因此是只能在 model 使用)。解决方案是:在 student.go 文件中引入工厂模式,首先给 student 写一个方法,该方法要求可以传入两个参数,一个是名字(n,string 类型),一个是成绩(s,float64)float,最终要要返回的类型是一个指针,代码为:func Newstudent(n string, s float64)*student {
返回时直接 return &student{,因为小写字母开头的结构体变量是可以在本包中使用,然后进行初始化(Name : n,score : s,),返回再看相当于在这个文件里面创建了一个student的对象实例然后返回,但是返回的时候是指针类型,这就意味着在其他包进行调用的时候,就是返回的数据本身。可以理解成这个数据空间是放在一个堆里面的,共享一个空间。写完之后进行全部保存,再在 main 文件中进行调用就会十分方便了,对main文件中的代码进行改进,完成对 student.go 文件中方法的调用,而且要把学生的信息传入进去,输入 var stu = model. Newstudent( "tom~",88.8)完成调用。实际上这个地方返回的是student的指针,所以在输出的时候也会出现信息前面加有&,运行后发现的确是这样的。对于student的信息,也是可以取出的,只需要在输出代码中添加*即可,即输出代码为:fmt.Print1n(*stu)fmt.Print1n("name=", stu.Name, " score=", stu.score)。这是因为虽然是指针,但是golang编译器底层会进行优化。
核心代码:
l
student.go
package model1
//定义一个结构体
type student struct{
Name string
score float64
}
//因为student结构体首字母是小写,因此是只能在model使用,我们通过工厂模式来解决
func Newstudent(n string, s float64)*student {
return &student{
Name : n,score : s,
}
}
l
main.go
package main
import(
"fmt"
"go_code/ chapter1e/factory/model"
)
func main(){
var stu = model. Newstudent( "tom~",88.8)
fmt.Print1n(*stu)
fmt.Print1n("name=", stu.Name, " score=", stu.score)
}
四、思考题
同学们思考一下,如果 model 包的 student 结构体的字段 Score 改成 score,我们还能正常访问吗?又应该如何解决这个问题呢?
思路:
如果把 Student 里面的 Score 改成小写的 score,保存后会发现会报错,改成小写以后成为不可导出的字段,因为现在是小写的,那么给 student 的结构体指针绑定一个方法并返回s,就可以解决问题。如果 score 字段首字母小写,则在其他包不可以直接访问,这时候我们可以提供一个方法.给 student 结构体指针绑定一个方法GetScore,然后返回放float64,代码为:func (s*student) Getscore( float64{
,输入return s.score返回。在这个包里面,s可以去访问score。因为小写字母就可以访问自身包的字段。输出方式为:fmt.Print1n("name=", stu.Name
, " score=", stu.GetsSore)
。因为方法是大写的,所以说方法本身是对外公开的,因此可以通过一个对外公开的方法去访问到私有的,或者不可导出的字段。
核心代码:
l
Student.go
package model
//定义一个结构体
type student struct{
Name string
score float64
}
//因为 student 结构体首字母是小写,因此只能在 model 中使用,可以通过工厂模式来解决
func NewStudent(n string, s float64)*student {
return &student{
Name : n,
score : s,
}
}
//如果 score 字段首字母小写,则在其它包不可以直接方法,此时我们可以提供一个方法,使其可以在其他包中使用。
func (s *student)Getscore() float64{
return s.score
}
l
Main.go
package main
import (
"fmt"
"go__code/ chapter1e/factory/model"
)
func main(){
var stu = mode1。Newstudent( "tom~",98.8)
fmt.Print1n(*stu)
fmt.Print1n("name=", stu.Name, " score=", stu.Getscore())
}