Golang 面向对象三大特性
优质
小牛编辑
140浏览
2023-12-01
封装性
封装性就是隐藏实现细节,仅对外公开接口
类是数据与功能的封装,数据就是成员变量,功能就是方法
为什么要封装?
- 不封装的缺点:当一个类把自己的成员变量暴露给外部的时候,那么该类就失去对该成员变量的管理权,别人可以任意的修改你的成员变量
- 封装就是将数据隐藏起来,只能用此类的方法才可以读取或者设置数据,不可被外部任意修改是面向对象设计本质(
将变化隔离
)。这样降低了数据被误用的可能(提高安全性
和灵活性
)
package model import "fmt" type Person struct { // 其它包也可用 name string // 当前包可用 age int // 当前包可用 } func (p *person)SetAge(age int) { // 安全校验 if age < 0 { fmt.Println("年龄不能为负数") } p.age = age }
package main import ( "fmt" "main/model" ) func main() { // 报错, 因为name和age不是公开的 //p := model.Person{"lnj", 18} // 方式一 //p := model.Person{} //p.SetAge(18) //fmt.Println(p) // 方式二 //p := new(model.Person) //p.SetAge(18) //fmt.Println(p) }
封装原则
将不需要对外提供的内容都隐藏起来,把属性都隐藏,提供公共的方法对其访问
继承性
Go 语言认为虽然继承能够提升代码的复用性,但是会让代码腐烂,并增加代码的复杂度.
所以 go 语言坚持了 组合优于继承 的原则,Go 语言中所谓的继承其实是利用组合实现的(匿名结构体属性)
普通继承(组合)
package main import "fmt" type Person struct { name string age int } type Student struct { Person // 学生继承了人的特性 score int } type Teacher struct { Person // 老师继承了人的特性 Title string } func main() { s := Student{Person{"lnj", 18}, 99} //fmt.Println(s.Person.name) fmt.Println(s.name) // 两种方式都能访问 //fmt.Println(s.Person.age) fmt.Println(s.age) // 两种方式都能访问 fmt.Println(s.score) }
继承结构中出现重名情况,采用就近原则
package main import "fmt" type Person struct { name string // 属性重名 age int } type Student struct { Person name string // 属性重名 score int } func main() { s := Student{Person{"zs", 18}, "ls", 99} fmt.Println(s.Person.name) // zs fmt.Println(s.name) // ls //fmt.Println(s.Person.age) fmt.Println(s.age) // 两种方式都能访问 fmt.Println(s.score) }
多重继承
package main import "fmt" type Object struct { life int } type Person struct { Object name string age int } type Student struct { Person score int } func main() { s := Student{Person{Object{77}, "zs", 33}, 99} //fmt.Println(s.Person.Object.life) //fmt.Println(s.Person.life) fmt.Println(s.life) // 三种方式都可以 //fmt.Println(s.Person.name) fmt.Println(s.name) // 两种方式都能访问 //fmt.Println(s.Person.age) fmt.Println(s.age) // 两种方式都能访问 fmt.Println(s.score) }
package main import "fmt" type Object struct { life int } type Person struct { name string age int } type Student struct { Object Person score int } func main() { s := Student{Object{77}, Person{"zs", 33}, 99} //fmt.Println(s.Person.life) fmt.Println(s.life) // 两种方式都可以 //fmt.Println(s.Person.name) fmt.Println(s.name) // 两种方式都能访问 //fmt.Println(s.Person.age) fmt.Println(s.age) // 两种方式都能访问 fmt.Println(s.score)
方法继承
在Go语言中子类不仅仅能够继承父类的属性,还能够继承父类的方法
package main import "fmt" type Person struct { name string age int } // 父类方法 func (p Person)say() { fmt.Println("name is ", p.name, "age is ", p.age) } type Student struct { Person score float32 } func main() { stu := Student{Person{"zs", 18}, 59.9} stu.say() }
继承中的方法重写
如果子类有和父类同名的方法,那么我们称之为方法重写
package main import "fmt" type Person struct { name string age int } // 父类方法 func (p Person)say() { fmt.Println("name is ", p.name, "age is ", p.age) } type Student struct { Person score float32 } // 子类方法 func (s Student)say() { fmt.Println("name is ", s.name, "age is ", s.age, "score is ", s.score) } func main() { stu := Student{Person{"zs", 18}, 59.9} // 和属性一样, 访问时采用就近原则 stu.say() // 和属性一样, 方法同名时可以通过指定父类名称的方式, 访问父类方法 stu.Person.say() }
注意点:无论是属性继承还是方法继承, 都只能子类访问父类, 不能父类访问子类
多态性
多态就是某一类事物的多种形态
猫: 猫-->动物
狗: 狗-->动物
男人 : 男人 -->人 -->高级动物
女人 : 女人 -->人 -->高级动物
Go 语言中的多态是采用接口来实现的
package main import "fmt" // 1.定义接口 type Animal interface { Eat() } type Dog struct { name string age int } // 2.实现接口方法 func (d Dog)Eat() { fmt.Println(d.name, "正在吃东西") } type Cat struct { name string age int } // 2.实现接口方法 func (c Cat)Eat() { fmt.Println(c.name, "正在吃东西") } // 3.对象特有方法 func (c Cat)Special() { fmt.Println(c.name, "特有方法") } func main() { // 1.利用接口类型保存实现了所有接口方法的对象 var a Animal a = Dog{"旺财", 18} // 2.利用接口类型调用对象中实现的方法 a.Eat() a = Cat{"喵喵", 18} a.Eat() // 3.利用接口类型调用对象特有的方法 //a.Special() // 接口类型只能调用接口中声明的方法, 不能调用对象特有方法 if cat, ok := a.(Cat); ok{ cat.Special() // 只有对象本身才能调用对象的特有方法 } }
多态优点
- 多态的主要好处就是简化了编程接口。它允许在类和类之间重用一些习惯性的命名,而不用为每一个新的方法命名一个新名字。这样,编程接口就是一些抽象的行为的集合,从而和实现接口的类的区分开来
- 多态也使得代码可以分散在不同的对象中而不用试图在一个方法中考虑到所有可能的对象。这样使得您的代码扩展性和复用性更好一些。当一个新的情景出现时,您无须对现有的代码进行改动,而只需要增加一个新的类和新的同名方法