【Golang】八、重点篇 --- 面向对象

封装、继承、多态

一、封装

封装可以使字段不直接暴露,通过自己封装的函数、结构体绑定的方法来初始化、获取或者修改等操作。(类似java中的构造函数、get、set的作用)

// 结构体都是小写,其他包无法访问到,所以需要封装一些方法去访问到该结构体
type person struct {
	number string
	Password string
}
// 初始化person结构体对象,并且返回该结构体执政
func NewPerson() *person {
	return &person{}
}

// 修改person中number字段的方法
func (p *person) SetNumber(number string) error  {
	if len(number) > 6 && len(number) < 10 {
		p.number = number
	} else {
		return errors.New("失败")
	}
	return nil
}

二、继承

1、匿名继承

  1. 结构体可以使用匿名继承的所有字段,方法(其中包含私有 or 公有的方法)
  2. 匿名结构体按照究竟访问原则,即子类结构体中如果有与父类相同字段numberp.number优先获取子类的number字段值;如果子类结构体中没有该字段,则结构体依次访问子类结构体的字段,直到找到为为止!!!
  3. 多继承关系,有多个父类结构体有相同字段(本身没有改同名字段),则必须使用结构体.父类结构体.字段获取该字段,否则编译异常。
type person struct {
	number string
	Password string
}
type HPerson struct {
	person
	Ext string
}

// person 绑定的方法
func (p *person) SetNumber(number string) error  {
	if len(number) > 6 && len(number) < 10 {
 		p.number = number
	} else {
		return errors.New("失败")
	}
	return nil
}

func main() {
	hp := HPerson{person: {"number", "password"}, Ext: "ext"}	
	// 匿名继承可以直接调用父类的字段属性和方法
	// 方法1
	hp.number = "123456"
	hp.SetNumber("1234567")
	// 方法2
	hp.person.number = "123456"
	hp.person.SetNumber("1234567")
}

2、具名继承

具名继承,故名思议,就是继承的结构体指定了名称(有些叫组合关系)
具名继承调用该结构体的方法、字段时,必须携带该结构体名,否则无法编译。
我们来对比下

  1. 匿名继承
    在这里插入图片描述

  2. 具名继承
    在这里插入图片描述

三、多态

golang中多态的特性主要是通过结构实现的

3-1 接口(引用类型)

  1. 什么是接口?
    interface可以定义一组方法,但都不需要实现。并且不包含任何变量。自定义结构体绑定方法需要使用时,再去实现接口中的方法。

  2. 如何使用?
    golang中的接口不需要任何显式实现。自定义变量需要实现接口所有的方法,呢么就可以实现接口的使用。

  3. 注意事项!

    • 一个类可以实现多个接口
    • 只要是自定义数据类型就可以实现接口
    • 一个接口A可以继承多个接口,实现A接口必须将B、C接口实现
    • 接口是引用类型,没有初始化,输出的是nil
  4. 接口快速搭建

    type Usb interface {
    	Start()
    	Stop()
    }
    
    // Phone结构体
    type Phone struct {
    	Number int
    }
    // Phone绑定的方法,实现Usb接口的方法
    func (p *Phone) Start() {
    	fmt.Println("Phone开始")
    }
    func (p *Phone) Stop() {
    	fmt.Println("Phone停止")
    }
    
    // Camera结构体
    type Camera struct {
    
    }
    // Camera绑定的方法,实现Usb接口的方法
    func (p *Camera) Start() {
    	fmt.Println("Camera开始")
    }
    func (p *Camera) Stop() {
    	fmt.Println("Camera停止")
    }
    
    // 电脑结构体
    type Computer struct {
    
    }
    // 接收一个usb接口类型的参数变量
    // 实现了usb接口
    func (c *Computer) Work(usb Usb) {
    	usb.Start()
    	fmt.Println("开始运行")
    	usb.Stop()
    }
    
  5. 接口变量
    指向接口变量的自定义数据类型,该类型下必须实现接口定义的方法

    // Phone指针类型的结构体绑定的方法
    // 所以也得是Phone指针类型的变量才有这些方法!!!!
    func (p *Phone) Start() {
    	fmt.Println("Phone开始")
    }
    func (p *Phone) Stop() {
    	fmt.Println("Phone停止")
    }
    
    func main(){
    	phone := &other.Phone{}
    	// 接口不可以实例化,但可以指向实现接口方法的自定义类型的变量
    	var myin other.Usb = phone
    }
    
  6. 范型的应用
    定义一个空接口,没有实现任何方法,即表示所有类都实现了该接口,可以接收任何类型的值,也就是常说的范型

    // 接收范型类型的参数
    func testFunc(i interface{}) {
    	fmt.Printf("%T\n", i)
    }
    func main(){
    	testFunc(1)
    	// 输出 =》int
    	testFunc(1.222)
    	// 输出 =》float64
    	testFunc("1")
    	// 输出 =》string
    }
    
  7. 源码案例:sort.Sort(data interface{})

    type Phones []int
    func (ps Phones) Len() int {
    	return len(ps)
    }
    func (ps Phones) Less(i, j int) bool {
    	return ps[i] < ps[j]
    }
    func (ps Phones) Swap(i, j int) {
    	ps[i], ps[j] = ps[j], ps[i]
    }
    func Sort() {
    	// 自定义类型Phones下实现了Sort接收接口参数的所有方法
    	// 所以直接将ps变量传递给接口,接口会指向ps绑定方法的内存地址,并且调用
    	ps := Phones{5,1,2,41,3}
    	// Sort 接收一个接口作为参数(该变量需要实现Len() Less() Swap() 方法)
    	sort.Sort(ps)
    	fmt.Println(ps)
    }
    

3-2 类型断言

类型断言是可以通过接口来转化成对应的自定义结构,相对于空接口来说,只可以转化成实现接口方法的自定义数据结构。

  1. 实现简单的接口断言
    断言转化后的数据类型,就相当于数据类型本身,可以调用该结构体自身的所有方法。
    转化公式:接收转化后的变量, 是否转化成功 := 接口变量.(类型)

    type Phone struct {
    	Number int
    }
    func (c *Computer) Work(usb Usb) {
    	// *Phone类型下有没有绑定这个方法
    	usb.Start()
    	fmt.Println("开始运行")
    	usb.Stop()
    
    	// 将usb转化为Phone类型
    	// 接收转化后的变量, 是否转化成功 := 接口变量.(类型)
    	phone, ok := usb.(*Phone)
    	if ok {
    		// 转化成功
    		fmt.Println(phone.Number)
    	} else {
    		// 转化失败
    		fmt.Println("不是Phone类型")
    	}
    }
    

    如果是未实现接口的类型,则会提示如下
    在这里插入图片描述

  2. switch和接口断言
    接口.(类型) 只适用于switch

    // 判断传入的类型
    func inters(TS ...interface{})  {
    	for _, T := range TS {
    		switch T.(type) { // 接口.(类型) 只适用于switch
    			case float64:
    				fmt.Println("float")
    			case string:
    				fmt.Println("string")
    			case other.Phone:
    				fmt.Println("Phone类型")
    			default:
    				fmt.Println("失败")
    		}
    	}
    }
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小鱼小鱼啊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值