GO语言学习之面向对象(4)之接口

GO语言学习之面向对象(4)接口

9.接口

9.1基本介绍

按其他语言顺序,应该学多态。因为在go中,多态的特性主要通过接口来体现的

9.2为什么有接口

我们可以想想一下,生活中,接口的应用场景,手机接口,相机接口

U盘接口,这些接口不管哪个厂家生产的都遵循这个接口

开发中也一样

9.3接口快速入门
package main

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
//接口声明所有方法
func (c Computer)Working(usb Usb)  {//usb变量会根据传入的实参,来
	//通过usb借口变量来调用 start 和 stop 方法
	usb.Start()
	usb.Stop()
}
func main() {
	//测试
	//先创建结构体变量
	computer:=Computer{}
	phone:=Phone{}
	camera:=Camera{}

	//关键点
	computer.Working(phone)
	computer.Working(camera)
}
9.4接口概念再说明

interface类型可以定义一组方法,但是这些不需要实现,并且interface不能包含任何自定义类型(比如结构体Phone)要使用的时候,在根据具体情况把这些方法写出来(实现)

9.5基本语法

type 接口名 interface{

method1(参数列表)返回值列表

method2(参数列表)返回值列表

}

func(t 自定义类型)method1(参数列表)返回值列表{

//方法实现

}

func(t 自定义类型)method2(参数列表)返回值列表{

//方法实现

}

》小结说明:

1》接口里所有方法都没有方法体,即接口的方法都是没有实现的方法。

接口体现了程序设计的多态和高内聚低耦合的思想

2》GO中的接口,不需要显式的实现。只要一个变量,所有接口类型中的

所有变量就实现这个接口。因此,GO中没有implement这样的关键字

9.6接口使用的应用场景

对初学者讲,理解接口的概念不算太难,难的是不知道什么时候使用接口。

1》现在我们要设计轿车,专家只需把汽车需要的功能/规格定下来即可,然后让别的人具体实现即可

2》说现在有一个项目经理,管理三个程序员,开发一个软件,为了控制和管理软件,项目经理可以定义一些接口,然后由程序员实现

9.7注意事项和细节

1》接口本身不能创建实例,但是可以指向一个实现了该接口的自定义类型的变量(实例)

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//结构体变量,实现了Say(),实现了 Ainterface
	var a AInterface=stu
	a.Say()
}

2》接口中所有的方法都没有方法体,即都是没有实现的方法

3》在go中,一个自定义类型需要将某个接口的所有方法都实现,我们说这个自定义类型实现了该接口

4》一个自定义类型只有实现了某个接口,才能将该自定义类型的实例(变量)赋给接口类型

5》只要是自定义数据类型,就可以实现接口,不仅仅是结构体类型

type integer int

func (i integer) Say() {
	fmt.Println("integer say i=",i)
}
	var i integer=10
	var b AInterface=i

	b.Say()

6》一个自定义类型可以实现多个接口

package main

import "fmt"

type AInterface interface {
	Say()
}
type BInterface interface {
	Sleep()
}


type Stu struct {
	Name string
}
func (Stu Stu)Say(){
	fmt.Println("stu say()")
}
func (Stu Stu)Sleep(){
	fmt.Println("stu sleep()")
}

func main() {
	var stu Stu//

	//Stu 实现了A接口 B接口

	var a AInterface=stu
	var b BInterface  =stu
	
	a.Say()
	b.Sleep()

}

7》go中的接口中不能有任何变量

type AInterface interface {
	Age String//报错
	Say()
}

8》一个接口(比如 A接口)可以继承多个别的接口(比如 B,C接口)

这时如果实现A接口,也必须将B,C接口的方法全部实现

package main

type BJIEKOU interface {
	testB()
}
type CJIEKOU interface {
	testC()
}

type AJIEKOU interface {
	BJIEKOU
	CJIEKOU
	testA()
}
//如果要实现A 接口,需要将 B 接口,C 接口的方法都实现
type Stud struct {
}


func (stu Stud)testB(){

}
func (stu Stud)testC(){

}
func (stu Stud)testA(){

}

func main() {
	var st Stud
	var a  AJIEKOU= st
	a.testA()
	a.testB()
	a.testC()

}

9》interface类型默认是一个指针(引用类型),如果没有对interface初始化就使用,那么就会输出nil

10》空接口interface{}没有任何方法,所以所有类型都实现了空接口,即我们可以把任何一个变量赋给空接口

package main

import "fmt"

//空接口 A
type A interface{}
//结构体 x
type STU struct{

	Name string
}

func main() {
	var x STU
	var a A=x//把变量赋给空接口
	if a == nil {
		fmt.Println("hello A")
	}else {
		fmt.Println("gogo ")
	}
}
9.8作业练习
package main

import "fmt"

//接口 A
type A interface{
	Test01()
	Test02()
}
//接口B
type B interface{
	Test01()
	Test03()
}
type Stu struct {

}
func (stu Stu)Test01() {

}
func (stu Stu)Test02() {

}

func (stu Stu)Test03() {

}


func main() {
	stu:=Stu{}
	var a A=stu
	var b B=stu
	fmt.Println("hello",a,b)
}


//hello {} {}
//下面代码,你能得出什么结论
package main

import "fmt"

//接口 A
type A interface{
	Test01()
	Test02()
}
//接口B
type B interface{
	Test01()
	Test03()
}
type Stu struct {

}
func (stu Stu)Test01() {

}
func (stu Stu)Test02() {

}

func (stu Stu)Test03() {

}

type C interface {
	A
	B
} 
//编译错误,因为C有两个test01(),编译器不能通过,报告重复定义
package main

import "fmt"

//接口 A
type A interface{
	Say()
}
type Stu struct {

}

func (this *Stu)Say()  {
	fmt.Println("Say()")
}
func main() {
	var stu Stu=Stu{}
	//var a A=stu//会报stu类型没有实现A接口
	var a A=&stu//这样能够实现
	a.Say()
}
9.9接口编程最佳实践

实现Hero结构体切片的排序:

sort.Sort(data Interface)

package main

import (
	"fmt"
	"math/rand"
	"sort"
)

//1.声明Hero结构体
type Hero struct {
	Name string
	Age int

}
//2.声明hero结构体的切片类型
type HeroSlice []Hero

//3。实现 Interface接口
func (hs HeroSlice)Len() int{
	return len(hs)
}
//Less方法决定你使用什么标准进行排序
//1.按照hero的年龄从小到大进行排序
func (hs HeroSlice)Less(i,j int) bool{
	return hs[i].Age<hs[j].Age
}
//swap 交换元素
func (hs HeroSlice)Swap(i,j int){
	temp:=hs[i]
	hs[i]=hs[j]
	hs[j]=temp
	//hs[i],hs[j]=hs[j],hs[i]  也可以写成这样进行交换变量
}
func main() {

	//先定义数组或者切片,进行排序
	var intSlice =[]int{0,9,7,8,1}
	fmt.Println(intSlice)
	//可以使用系统提供的sort方法进行排序
	sort.Ints(intSlice)
	fmt.Println(intSlice)

	//对结构体进行排序

//测试我们能否对结构体切片进行排序
	var heroes HeroSlice
	for i:=0;i<10;i++{
		hero:=Hero{
			Name: fmt.Sprintf("英雄-%d",rand.Intn(100)),
			Age:  rand.Intn(100),
		}
		//将hero 添加到 heros切片中
		heroes=append(heroes,hero)
	}
	//排序前
	for _,v:=range heroes{

		fmt.Println(v)
	}
	//排序
	sort.Sort(heroes)
	//排序后
	fmt.Println("排序后")
	for _,v:=range heroes{

		fmt.Println(v)
	}

}

接口编程练习:

//1.声明Stu结构体,将 student按照分数进行排序

type Stu struct {
	Name string
	Age int
	Score float64
}

package main

import (
	"fmt"
	"math/rand"
	"sort"
)

//1.声明Stu结构体,将 student按照分数进行排序

type Stu struct {
	Name string
	Age int
	Score float64
}
//2.声明 Stu 结构体切片
type  StuSlice []Stu

//3.实现interface接口
//1>实现Len()方法
func (ss StuSlice)Len()int{
	return len(ss)
}
//2>实现 Less()
func (ss StuSlice)Less(i,j int)bool{

	return ss[i].Score>ss[j].Score
}
//3>实现 Swap()
func (ss StuSlice)Swap(i,j int){
	ss[i],ss[j]=ss[j],ss[i]
}

func main() {

	var stu StuSlice

	for i:=0;i<5;i++{
		s:=Stu{
			Name: fmt.Sprintf("学生-%d",rand.Intn(100)),
			Age:  rand.Intn(20),
			Score:float64(rand.Intn(100)),
		}
		//将hero 添加到 heros切片中
		stu=append(stu,s)
	}

	//排序前
	fmt.Println("排序前:")
	for _,v:=range stu{
		fmt.Print(v,"  ")
	}
	fmt.Println()
	//排序
	sort.Sort(stu)
	fmt.Println("排序后:")
	for _,v:=range stu{
		fmt.Print(v,"  ")
	}
	fmt.Println()
}
9.10实现接口 vs 继承
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,"生来会爬树")
}

//SmallMonkey结构体
type SmallMonkey struct {
	Monkey//继承
}
//让SmallMonkey实现 BirdAble
func (this *SmallMonkey)Flying(){
	fmt.Println(this.Name,"通过学习,能够飞行")
}
//让 smallMonkey实现fishAble
func (this *SmallMonkey)Swimming(){
	fmt.Println(this.Name,"通过学习,能够游泳")
}

func main() {
	//创建一个 SmallMonkey实例

	mon:=SmallMonkey{Monkey{Name:"孙大圣"}}

	mon.climbing()
	mon.Flying()
	mon.Swimming()
}

对上面代码进行总结:

1》当 A结构体继承了B结构体,那么A结构体就自动

继承了B结构体的字段和方法,并且可以直接使用

2》当A结构体需要扩展功能,同时不希望去破坏继承关系,则可以去

实现某个接口即可,因此我们可以认为:

实现接口是对继承机制的补充

》接口和继承解决的问题不同

继承的价值主要在于:解决代码的复用性和可维护性

接口的价值主要在于:设计,设计好各种规范(方法),让其它自定义类型去实现这些方法

》接口比继承更加灵活:

接口比继承更加灵活,继承满足的是 is -a 的关系,而接口只需满足 like -a的关系

》接口在一定程度上实现了代码解耦

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值