面向对象
封装
封装就是把抽象出的字段和对字段的操作封装在一起,数据被保护在内部,程序的其他包只有通过被授权的操作(方法),才能对字段进行操作。
//封装
//不能随便查看人的工资等隐私,并对输入的年龄进行合理的验证
type person struct {
Name string
age int
wage float64
}
func NewPerson(name string) *person {
return &person{
Name: name,
}
}
func (p *person) SetAge(age int) {
if age < 0 || age > 130 {
fmt.Println("你输入的年龄不合理")
return
}
p.age = age
}
func (p *person) GetAge() int {
return p.age
}
func (p *person) SetWage(wage float64) {
if wage < 0 {
fmt.Println("你输入的薪水不合理")
return
}
p.wage = wage
}
func (p *person) GetWage() float64 {
return p.wage
}
好处:
- 隐藏实现细节
- 提前对对数据验证
如何体现封装:
- 对结构体中的属性进行封装
- 使用方法和包实现封装
封装的实现步骤
- 将结构体、字段(属性)的首字母小写(不能导出了,其它包不能使用,类似 private)
- 给结构体所在包提供一个工厂模式的函数,首字母大写。类似一个构造函数
- 提供一个首字母大写的 Set 方法(类似其它语言的 public),用于对属性判断并赋值
func (var 结构体类型名) SetXxx(参数列表) (返回值列表) {
//加入数据验证的业务逻辑
var.字段 = 参数
} - 提供一个首字母大写的 Get 方法(类似其它语言的 public),用于获取属性的值
func (var 结构体类型名) GetXxx() {
return var.age;
}
特别说明:在 Golang 开发中并没有特别强调封装,这点并不像 Java. 所以提醒学过 java 的朋友,
不用总是用 java 的语法特性来看待 Golang, Golang 本身对面向对象的特性做了简化的.
继承
继承可以解决代码复用,让我们的编程更加靠近人类思维。
当多个结构体存在相同的属性(字段)和方法时,可以从这些结构体中抽象出结构体,在该结构体中定义这些相同的属性和方法。其它的结构体不需要重新定义这些属性(字段)和方法,只需嵌套一个 Student 匿名结构体即可。
import "fmt"
// 继承
type Student struct {
Name string
Age int
Score float64
}
type Pupil struct {
Grade string
Student
}
type Graduate struct {
Grade string
Student
}
// 展示他的成绩
func (s *Student) ShowInfo() string {
return fmt.Sprintf("name: %s, age: %d, score: %f", s.Name, s.Age, s.Score)
}
func (s *Student) SetScore(score float64) {
//业务判断
s.Score = score
}
func (s *Student) testing(Grade string) {
fmt.Printf("%s正在考试\n", Grade)
}
func main() {
var p *Pupil = &Pupil{
Grade: "小学生",
Student: Student{
Name: "Tom",
Age: 10,
},
}
var graduate *Graduate = &Graduate{
Grade: "大学生",
Student: Student{
Name: "Jack",
Age: 20,
},
}
p.testing(p.Grade)
p.SetScore(99.0)
fmt.Println(p.ShowInfo())
fmt.Println("---------------------")
graduate.testing(graduate.Grade)
graduate.SetScore(60.0)
fmt.Println(graduate.ShowInfo())
}
上面代码中Graduate 和 Pupil 结构体中分别嵌套了Student 这个结构体,继承了Student中的字段和方法。
继承的细节
1.结构体可以使用嵌套匿名结构体所有的字段和方法, 即:首字母大写或者小写的方法,字段都可以使用
2.当结构体和匿名结构体有相同的字段或者方法时,编译器采用就近访问原则访问,如希望访问匿名结构体的字段和方法,可以通过匿名结构体名来区分
3.如果一个 struct 嵌套了一个有名结构体,这种模式就是组合,如果是组合关系,那么在访问组合的结构体的字段或方法时,必须带上结构体的名字
type D struct{
a A //有名结构体
}
var d D
d.a.Name="jack"
多重继承
如一个 struct 嵌套了多个匿名结构体,那么该结构体可以直接访问嵌套的匿名结构体的字段和方法,从而实现了多重继承。
type Goods struct{
Name string
Price float64
}
type Brand struct{
Name string
Address string
}
type TV struct{
Goods
Brand
}
多重继承的细节
1.如嵌入的匿名结构体有相同的字段名或者方法名,则在访问时,需要通过匿名结构体类型名来区分。
- 为了保证代码的简洁性,建议大家尽量不使用多重继承
继承和接口的区别
1.当 A 结构体继承了 B 结构体,那么 A 结构就自动的继承了 B 结构体的字段和方法,并且可以直接使用
- 当 A 结构体需要扩展功能,同时不希望去破坏继承关系,则可以去实现某个接口即可,因此我们可以认为:实现接口是对继承机制的补充. 实现接口可以看作是对继承的一种补充
3.接口和继承解决的解决的问题不同:
继承的价值主要在于:解决代码的复用性和可维护性。
接口的价值主要在于:设计好各种规范(方法),让其它自定义类型去实现这些方法。
接口比继承更加灵活: 继承是满足 is - a 的关系,而接口只需满足 like - a 的关系。接口在一定程度上实现代码解耦
多态
在Go语言中,多态特征是通过接口实现的,可以按照统一的接口来调用不同的实现。这时接口变量就呈现不同的形态。
体现多态的两种形式
多态参数
在下面的 Usb 接口案例,Usb usb ,即可以接收手机变量,又可以接收相机变量,就体现了 Usb 接口多态。
//多态参数
import (
"fmt"
)
// 声明/定义一个接口
type Usb interface {
//声明了两个没有实现的方法
Start()
Stop()
}
type Phone struct {
}
// 让 Phone 实现 Usb 接口的方法
func (p Phone) Start() {
fmt.Println("手机开始工作。。。")
}
func (p Phone) Stop() {
fmt.Println("手机停止工作。。。")
}
type Camera struct {
}
// 让 Camera 实现 Usb 接口的方法
func (c Camera) Start() {
fmt.Println("相机开始工作。。。")
}
func (c Camera) Stop() {
fmt.Println("相机停止工作。。。")
}
type Computer struct {
}
// 编写一个方法 Working 方法,接收一个 Usb 接口类型变量
// 只要是实现了 Usb 接口 (所谓实现 Usb 接口,就是指实现了 Usb 接口声明所有方法)
// 这一步其实就实现了多态(usb Usb)就是多态参数
func (c Computer) Working(usb Usb) { //usb 变量会根据传入的实参,来判断到底是 Phone,还是 Camera
//通过 usb 接口变量来调用 Start 和 Stop 方法
usb.Start()
usb.Stop()
}
func main() {
//测试
//先创建结构体变量
computer := Computer{}
phone := Phone{}
camera := Camera{}
//关键点
computer.Working(phone)
computer.Working(camera) //
}
多态数组
演示一个案例:给 Usb 数组中,存放 Phone 结构体 和 Camera 结构体变量
//多态数组
import (
"fmt"
)
// 声明/定义一个接口
type Usb interface {
//声明了两个没有实现的方法
Start()
Stop()
}
type Phone struct {
name string
}
// 让 Phone 实现 Usb 接口的方法
func (p Phone) Start() {
fmt.Println("手机开始工作。。。")
}
func (p Phone) Stop() {
fmt.Println("手机停止工作。。。")
}
type Camera struct {
name string
}
// 让 Camera 实现 Usb 接口的方法
func (c Camera) Start() {
fmt.Println("相机开始工作。。。")
}
func (c Camera) Stop() {
fmt.Println("相机停止工作。。。")
}
func main() {
//定义一个Usb接口数组,可以存放Phone和Camera的结构体变量
//这里就体现出多态数组
var usbArr [3]Usb
usbArr[0] = Phone{"荣耀"}
usbArr[1] = Phone{"小米"}
usbArr[2] = Camera{"索尼"}
fmt.Println(usbArr)
}

被折叠的 条评论
为什么被折叠?



