Go面向对象三大特性

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()
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值