Go 面向对象三大特性
#### Go 中面向对象的三大特性
上周因为有一些事情,停更了; 停更的这段时间,花了点时间做了一个小项目(https://github.com/yioMe/node_wx_alipay_personalPay)
原项目由node.js 写的,根据文档用Go 重写了(Gin + MySQL) ;
1. 没有了繁琐的node安装;
2. 没有 DB 迁移;
3. 支付成功回调优化;
4. 性能提升;
5. 修复了上传二维码不能识别的问题;
不过只重写了一小部分功能,应对日常个人支付不成问题,如有需要了解的朋友,私聊一同交流学习;
---
言归正传,Go 中的面向对象的特性与传统的OOP 语言不同,我们来一一学习了解;
###### 封装
封装就是把抽象的字段的对字段的操作封装在一起,数据被保护在内部,程序中的其它包只能通过被授权的操作才能对
字段操作;
封装的好处:
1. 隐藏实现的细节;
2. 可以对数据进行验证,保证数据的安全合理;
---
封装实现的步骤:
1. 将结构体,字段的首字母小写,不能被导出,其它包不能使用,类似JAVA 的private ;
2. 在结构体所在的包提供一下工厂模式的函数,首写字母大写,类似构造函数;
3. 提供一个首字母大写的Set 方法,用于对属性的判断并赋值
4. 提供一个首字母大写的Get 方法,用于获取属性的值;
5. 在Go 中没有特别强调封装,所以有其它编程语言的朋友,不需要用其它的语法特性来学习Go, 每种编程语言都有各自的特点;
package model import "fmt" type student struct { Name string age int // 其它的包不能直接访问 score float64 // 其它的包不能直接访问 } // 工厂方法,相当于构造函数 func NewStudent(name string) *student{ return &student{ Name:name, } } // 为了访问和更改结构体的属性,编写一对GetXxx/SetXxx 的方法 // this 只是接收类型的名称, 可以命名为任意合法的标识符 func (this *student) GetAge() int { return this.age } func (this *student) SetAge(age int){ // 可以在Set 方法里对数据进行校验 if age < 0 || age > 100 { fmt.Println("age is wrong") return } this.age = age } func (this *student) GetScore() float64{ return this.score } func (this *student) SetScore(score float64) { if score < 0 || score > 100 { fmt.Println("score is wrong") return } this.score = score }
package main import ( "fmt" "personalPayment/model" ) func main(){ p := model.NewStudent("jack") p.SetAge(20) p.SetScore(200) fmt.Println(*p) fmt.Println(p.Name,"age=",p.GetAge(),"score=",p.GetScore()) }
---
###### 继承
1. 继承可以解决代码的复用问题
2. 当多个结构体有相同的属性和方法时,可以从这些结构体中抽象一下基础的结构体,在该结构体中定义相同的属性和方法;
3. Go 中实现继承是通过结构体匿名嵌套来实现;
基本语法:
type Person struct {
Name string
Age int
}
type Student struct {
Person // 嵌套的结构体,实现继承
Score float64
}
案例:
package model import "fmt" type person struct { Name string age int } type student struct { person score float64 // 其它的包不能直接访问 } type teacher struct { person class string } // 学生的工厂方法,相当于构造函数 func NewStudent(name string) *student{ return &student{ person:person{ Name:name, }, } } // 老师的工厂方法 func NewTeacher(name string) *teacher{ return &teacher{person:person{ Name:name, }} } // 基础结构的公众方法 func (this *person) GetAge() int { return this.age } func (this *person) SetAge(age int){ // 可以在Set 方法里对数据进行校验 if age < 0 || age > 100 { fmt.Println("age is wrong") return } this.age = age } // 学生的方法 func (this *student) GetScore() float64{ return this.score } func (this *student) SetScore(score float64) { if score < 0 || score > 100 { fmt.Println("score is wrong") return } this.score = score } // 老师的方法 func (this *teacher) GetClass() string { return this.class } func (this *teacher) SetClass(class string){ this.class = class }
package main import ( "fmt" "personalPayment/model" ) func main(){ s := model.NewStudent("jack") // 调用公用的结构体方法 s.SetAge(20) // 调用自己的方法 s.SetScore(100) fmt.Println(s.Name,s.GetAge(),s.GetScore()) t := model.NewTeacher("tom") // 调用公用的结构体方法 t.SetAge(40) // 调用自己的方法 t.SetClass("English") fmt.Println(t.Name,t.GetAge(),t.GetClass()) }
继承的使用和注意事项
1. 结构体可以使用嵌套匿名的结构体中的所有的属性和方法,不论大写与小写
2. 结构体中匿名结构体的字段和方法可以简化;
3. 当结构体和匿名结构体有相同的属性和方法时,编译器采用就近原则,如果需要访问匿名结构体中的字段
和方法需要通过匿名结构体的名称来区分;
4. 如果一个结构体嵌套了一个有名称的结构体,这种模式称为组合,在访问组合的结构体或方法时需要加上结构体的名字;
package main import ( "fmt" ) type person struct { Name string Age int skill string } type student struct { person score float64 } func (p *person) Say(){ fmt.Println("I am a person") } func (p *person) Do(){ fmt.Println("I am doing something") } type A struct { Name string } type B struct { A Name string } type C struct { Name string } type D struct { c C Age int } func main(){ s := &student{} s.person.Say() s.person.Do() s.person.Name = "jack" s.person.Age = 20 s.person.skill = "speak" fmt.Println(*s) // 对匿名结构体中的属性方法可以简化为 s.Say() s.Do() s.Name = "jack2" s.Age = 21 s.skill = "laugh" fmt.Println(*s) // 如果结构体和匿名结构体中有相同的属性或方法,编译器将采用就近原则, // 如果需要访问匿名结构体的属性和方法需要通过匿名结构体的名称 a := B{ A: A{ Name:"aaa", }, Name:"bbb", } fmt.Println(a.Name) // bbb fmt.Println(a.A.Name) // aaa // 对于组合,在访问继承结构体的方法或属性时需要加上结构体的名称 d := D{ c:C{Name:"ccc"}, Age:20, } fmt.Println(d.Age) // 自己的属性 fmt.Println(d.c.Name) // 访问继承的属性 }
个人微信公众号上有最新文章,欢迎关注一同交流学习
每天进步一点点!加油