面向对象特征,继承,封装,多态。在go中是使用技巧来实现这三个特征。
封装介绍
封装(encapsulation)就是把抽象出的字段和对字段的操作封装在一起,数据被保护在内部,程序的其它包只有通过被授权的操作(方法),才能对字段进行操作。
有些字段你是不希望公开的,那么就将对象作为私有的。字段首字母小写之后就对这个字段提供一个公开的方法让别人去操作,这个就叫做封装,将对字段和对字段的操作放在一起。
对电视机的操作就是最好的例子:电视机的操作要将音量调大就需要通过遥控器按下按钮就行了,但是内部的结构并不需要我们去管理。
同理对字段的操作只需要调用其方法就行了
下面这种命名无法通过跨包去实例化,即使能实例化,也无法给socre赋值,通常这种命名方式,是为了放一些私属性,不给外部(跨包)直接使用
type student struct{
Name string
score float32
}
封装的理解和好处
1)隐藏实现细节
2)提可以对数据进行验证,保证安全合理
提供一个方法对成员进行操作,在操作之前提供校验数据的有效性来保证安全合理
如何体现封装
1)对结构体中的属性进行封装
2)通过方法,包实现封装
封装的实现步骤
1)将结构体、字段(属性)的首字母小写(不能导出了,其它包不能使用,类似private)
2)给结构体所在包提供一个工厂模式的函数,首字母大写,类似一个构造函数
3)提供一个首字母大写的Set方法(类似其它语言的public),用于对属性判断并赋值
func( struct_name 结构体类型名) SetXxx(参数列表) (返回值列表){
//加入数据验证的业务逻辑
struct_name.字段=参数
}
4)提供一个首字母大写的Get方法(类似其它语言的public),用于获取属性的值
func(struct_name 结构体类型名) GetXxx() 字段类型{
return struct_name.字段
}
特别说明:在Golang开发中并没有特别强调封装,这点并不像Java.所以提醒学过java的朋友,不用总是用java的语法特性来看待Golang,Golang本身对面向对象的特性做了简化的.
封装-工厂模式
-
golang的结构体没有构造函数(比如get set函数去设置你的结构体属性),通常可以使用工厂模式来解决这个问题。(当我去跨包使用的时候,虽然结构体尽量大写,但是有些时候需要作为私密的变量,我不想让其跨包使用,那么变量名称就小写,但是有些时候跨包还是想拿到这个东西,那么就可以封装一个方法)
-
如果包里面的结构体变量首字母小写,引入后,不能直接使用,可以工厂模式解决(封装成方法,通过方法跨包调用)。
-
只关心结果,不关心实现过程,因为过程是由封闭的工厂来实现的(能不能get set,不关心中间做了什么,不关系作用域,不关心大写小写)
package demo
//定义一个结构体
type student struct{
Name string
score float64
}
//*student返回结构体的指针,new函数是函数,不是方法,不需要添加接收器,通过包名点出来就行了
//跨包的时候可以去调这个函数去实例化对象
func NewStudent(name string, score float64) *student {
//外包引用不了,但本包是可以引用的
stu := student{
Name : name,
score : score,
}
return &stu
}
//接收器能够使用指针类型尽量使用指针类型
//结构体中的score字段也是小写所以需要写一个方法返回(get和结构体走,那么不能使用函数,使用方法)
func (s *student) GetScore() float64 {
return s.score
}
//使用方法和结构体绑定
func (s *student) SetScore(score float64) {
//这里可以对score做校验,校验通过了才可以赋值
s.score = score
}
func main() {
s := demo.NewStudent("Tony", 60.5)
fmt.Println(s)
fmt.Println(s.GetScore())
s.SetScore(80)
fmt.Println(s)
//&{Tony 60.5}
//60.5
//&{Tony 80}
}
工厂函数
工厂函数一般用于创建自定义的结构体,便于使用者调用,我们还是以 person 类型为例,用如下代码进行定义:
func NewPerson(name string) *person {
return &person{name:name}
}
我定义了一个工厂函数 NewPerson,它接收一个 string 类型的参数,用于表示这个人的名字,同时返回一个*person。
通过工厂函数创建自定义结构体的方式,可以让调用者不用太关注结构体内部的字段,只需要给工厂函数传参就可以了。
用下面的代码,即可创建一个*person 类型的变量 p1:
p1:=NewPerson("张三")
工厂函数也可以用来创建一个接口,它的好处就是可以隐藏内部具体类型的实现,让调用者只需关注接口的使用即可。
总结就是结构体有些东西是隐秘的,但是只有在我的包里面能改,但是跨包看可以控制其权限范围,提供比如set方法,只关心结果就行了。