Go面向对象三大特性
三大特性之一:封装
-
把抽象出的字段和对字段的操作封装在一起,数据被保护在内部,程序的其他包只有通过授权的操作(方法)才能对字段进行操作
-
封装好处
- 隐藏实现细节
- 对数据进行验证,保证安全合理
-
体现封装
- 对结构体中的属性进行封装
- 通过方法,包实现封装
-
封装实现
-
将结构体、字段的首字母小写
-
给结构体所在包提供一个工厂模式的函数,首字母大写
-
提供一个首字母大写的Set方法,用于对属性判断并赋值
-
func (var 结构体类型名)SetXXX(参数列表)(返回值列表){ //加入数据验证的参数 var 字段 = 参数 }
-
-
提供一个首字母大写的Get方法,用于获取属性的值
-
func (var 结构体类型名)GetXXX(){ return var.age }
-
-
-
案例
-
package main import ( "fmt" "go_code/project01/model" ) func main(){ p := model.NewPerson("smith") p.SetAge(18) p.SetSal(5000) fmt.Println(*p) fmt.Println(p.Name,"age=",p.GetAge(),"sal=",p.GetSal()) }
-
package model import "fmt" type person struct { Name string age int sal float64 } //写一个工厂模式函数 func NewPerson(name string) *person { return &person { Name : name, } } //为了访问age和sal 编写一对Set和Get的方法 func (p *person) SetAge (age int) { if age > 0 && age < 150 { p.age = age } else { fmt.Println("年龄范围不正确") } } func (p *person) GetAge()int { return p.age } func (p *person) SetSal (sal float64) { if sal >= 3000 && sal <= 30000 { p.sal = sal } else { fmt.Println("薪水范围不正确") } } func (p *person)GetSal()float64 { return p.sal }
-
三大特性之一:继承
-
在Golang中,如果一个结构体struct嵌套了另一个匿名结构体,那么这个结构体可以直接使用匿名结构体的字段和方法,从而体现继承
-
type Goods struct { Name string Price int } type Book strcut { Goods//嵌套匿名结构体 Writer string }
-
package main import "fmt" //结构体可以骑使用嵌套匿名结构液体所有字段和方法,首字母小写的也可以 type A struct { Name string age int } func (a *A) Sayok(){ fmt.Println("A SayOK",a.Name) } func (a *A)hello(){ fmt.Println("A hello",a.Name) } type B struct { A Name string } func (b *B) SayOK(){ fmt.Println("B SayOK",b.Name) } type D struct { a A//有名结构体 } type Goods struct { Name string Price float64 } type Brand struct { Name string Address string } type TV struct { Goods Brand } type Monster struct { Name string Age int } //如果一个结构体有int类型的匿名字段,就不能有第二个 //如果需要多个int的字段,就必须给int字段指定名字 type E struct { Monster int } func main(){ var b B //匿名结构体字段访问可以简化 //编译器会先看b对应的类型有没有Name,有就直接调用B类型的Name字段 //如果没有就去B的嵌套匿名结构体A有没有声明Name字段,如有就调用,没有就报错 b.A.Name = "tom" b.Name = "tom" b.A.age = 19 b.age = 19 b.A.hello() b.hello() b.A.Sayok() b.Sayok() //当结构体和匿名结构体有相同的字段或方法时,编译器采用就近原则访问 //如希望访问匿名结构体的方法或字段,可以通过匿名结构体名来区分 b.Name = "jack" b.age = 100 b.Sayok()//B SayOK jack b.hello()//A hello "" b.A.Name = "scott" b.hello()//A hello scott //结构体嵌入两个或多个匿名结构体,如两个匿名结构体有相同的字段和方法 //同时结构体本身没有同名的字段和方法,在访问时,就必须明确指定匿名结构体名字 //否则编译器报错 //如果一个struct嵌套了一个有名结构体,这种模式就是组合 //如果是组合关系,那么在访问组合的结构体的字段或方法时 //必须带上结构体的名字 var d D //d.Name = "jack"会报错 d.a.Name = "jack" //嵌套匿名结构体后,可以在创建结构体变量(实例)时,直接指定各个匿名结构体字段的值 tv1 := TV{Goods{"电视机001",5000.99},Brand{"海尔","山东"},} tv2 := TV{ Goods{"电视机002", 5000.88, }, Brand{"海尔", "山东", }, } fmt.Println("tv",tv1) fmt.Println("tv",tv2) //匿名字段是基本数据类型的使用 var e E e.Name = "狐狸精" e.Age = 300 e.int = 20 fmt.Println("e=",e) }
-
多重继承
- 如一个struct嵌套了多个匿名结构体,那么该结构体可以直接访问嵌套匿名结构体的字段和方法,从而实现多重继承
接口
package main
import "fmt"
//interface类型可以定义一组方法,但不需要实现,并且interface不能包含任何变量
//到某个自定义类型要使用是,再根据具体情况将方法写出来(实现)
//接口哩的所有方法都没有方法体,即接口的方法都是没有实现的方法
//接口体现了程序设计的多态和高内聚低偶合的思想
//Golang中的接口不需要显示实现,只需要一个变量,含有接口类型中的所有方法
//那么这个变量就实现了这个接口
//Golang中没有implement这样的关键字
//声明/定义一个接口
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 (p Camera) Start(){
fmt.Println("相机开始工作")
}
func (p Camera) Stop(){
fmt.Println("相机停止工作")
}
type Computer struct {
}
//编写一个方法working,接收一个Usb接口类型变量
//只要是实现了Usb接口即实现了Usb接口声明的所有方法
func (c Computer)Working(usb Usb){
//通过usb接口变量来调用Start和Stop方法
usb.Start()
usb.Stop()
}
func main(){
//创建结构体变量
c := Computer{}
phone := Phone{}
camera := Camera{}
c.Working(phone)
c.Working(camera)
}
接口的注意实项和细节
package main
import "fmt"
type AInterface interface {
Say()
}
type Stu struct {
Name string
}
func (stu Stu) Say(){
fmt.Println("Stu Say()")
}
func main(){
//接口本身不能创建实例,但是可以指向一个实现了该接口的自定义类型的变量(实例)
var stu Stu
var a AInterface = stu
a.Say()
//在Golang中,一个自定义类型需要将某个接口的所有方法都实现,才算这个自定义类型实现了该接口
//一个自定义类型只有实现了某个接口,才能将该自定义类型的实例赋给接口类型
//只要是自定义数据类型,就可以实现接口,不仅仅是结构体
//一个自定义类型可以实现多个接口
//Golang接口中不能有任何变量
//一个接口(A)可以继承多个别的接口(B、C),如果要实现A接口,必须将BC接口的方法也全部实现
//interface类型默认是一个指针(引用类型),如果没有对interface初始化就使用,会输出nil
//空接口interface{}没有任何方法,所以所有类型都实现了空接口
}
接口与继承
package main
import "fmt"
//Monkey结构体
type Monkey struct {
Name string
}
type BirdAble interface {
Flying()
}
type FishAble interface {
swimming()
}
func (this *Monkey) climbing {
fmt.Println(this.Name,"生来会爬树")
}
//LittleMonkey结构体
type LittleMonkey struct {
Monkey
}
func (this *LittleMonkey) Flying(){
fmt.Println(this.Name,"通过学习,会飞翔")
}
func (this *LittleMonkey)Swimming(){
fmt.Println(this.Name,"通过学习,会游泳")
}
func main(){
monkey := LittleMonkey{
Monkey{
Name: "悟空",
},
}
monkey.climbing()
monkey.Flying()
monkey.Swimming()
//当结构体A继承了B结构体,那么A结构就自动继承了B结构体的字段和方法,并且可以直接使用
//当A结构体需要扩展功能时,同时不破坏继承关系
//可以实现某个接口,实现接口是对继承机制的补充
}
三大特性之一:多态
- 多态特征是通过接口实现的,可以按照统一的接口来调用不同的实现
类型断言
package main
import "fmt"
type Point struct{
x int
y int
}
func main(){
var a interface{}
var point Point = Point{1,2}
a = point //ok
var b Point
//b = a err
b = a.(Point)//类型断言
//表示判断a是不是指向Point类型的变量,如果是就转成point类型并赋给b变量,否则报错
fmt.Println(b)
//类型断言
//由于接口是一般类型,不知道具体类型
//如果要转成具体类型,就必须使用类型断言
//类型断言,带检测
var x interface{}
var b2 float32 = 2.1
x = b2//空接口,可以接受任何类型
if y,ok := x.(float32); ok{
fmt.Println("convert success")
fmt.Printf("y 的类型是%T 值是%v",y,y)
} else {
fmt.Println("convert fail")
}
fmt.Println("继续执行")
}
package main
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("手机停止工作")
}
func (p Phone)Call(){
fmt.Println("手机打电话")
}
type Camera struct {
name string
}
//让Camera实现Usb接口方法
func (p Camera) Start(){
fmt.Println("相机开始工作")
}
func (p Camera) Stop(){
fmt.Println("相机停止工作")
}
type Computer struct {
}
//编写一个方法working,接收一个Usb接口类型变量
//只要是实现了Usb接口即实现了Usb接口声明的所有方法
func (c Computer)Working(usb Usb){
//通过usb接口变量来调用Start和Stop方法
usb.Start()
//如果usb是指向Phone结构体变量,则还需要调用call方法
if phone,ok := usb.(Phone);ok{
Phone.Call()
}
usb.Stop()
}
func main(){
var usbArr[3]Usb
usbArr[0]=Phone{"vivo"}
usbArr[1]=Phone{"小米"}
usbArr[2]=Phone{"尼康"}
var computer Computer
for _,v := range usbArr {
computer.Working(v)
fmt.Println()
}
}