Go语言入门到实战——11.Go语言相关接口(面向对象知识)

本文介绍了Go语言中接口的使用、依赖管理、DuckType接口实现、多态以及空接口和断言。重点讲述了如何避免循环依赖,利用DuckType实现接口抽象,以及Go语言不支持继承但通过复用和内嵌进行代码复用。
摘要由CSDN通过智能技术生成

Go语言入门到实战——00主目录
在上一讲中我们学习了Go语言的面向对象的知识。

一.接口与依赖


首先看上图,A是一个接口,而AImpl则是这个接口的实现,AClient则是创建了AImpl对象并且调用了接口的方法,那么出现了上面的依赖情况,现在假设我们把A和AClient放在一个包里面,而AImpl放在另外一个包里面,那么这个时候会出现循环依赖的问题,那么我们一般就要注意不能这样建包,一般接口是单独放在一个包的。

二.Duck Type式接口实现

package test

import "testing"

type Programmer interface {
	WriteHelloWorld() string
}

type GoProgrammer struct {
}

func (g *GoProgrammer) WriteHelloWorld() string {
	return "I am Jack"
}

func TestClient(t *testing.T) {
	p := new(GoProgrammer)//new一个实例对象,返回指针类型
	t.Log(p.WriteHelloWorld())
}

上面可能看起来会比较奇怪就是感觉好像并没有实现接口的意思,其实这是Go语言的Duck Type类型做法,
就是我们定义了接口Programmer,那么结构体GoProgrammer的方法和Programmer的方法一模一样(参数
,函数名,返回值),这种看起来很形象的像鸭子一样的东西,不知道是什么鸟,但是很像,这就是Duck Type,
这样我们就认为实现了接口,这里·就给我们一个启发,就是以后我们再编程写结构体,想加个接口进行抽象化,
这时也不需要将原来的结构体加个啥implments啥的,比较形象方便

这里我们做个总结:

1.go接口是非入侵性质的,实现不依赖于接口的定义
2.所以接口的定义可以包含在接口使用者里面(就是本文第一小节讲解的Interface和Client放在一个包),
这也是Go和主流语言的一个区别

三.接口变量与自定义变量

1.接口变量
var prog Programmer = &GoProgrammer{}//Programmer是接口类型,GoProgrammer是其实现
2.自定义类型(举例说明)
type MyInt int64//自定义变量类型
type MyFunc func(int,int) string//自定义函数类型

四.扩展和复用(Go不支持继承)

这一节主要介绍下Go语言是不支持继承的,主要做复用(其他语言的常见做法)和Go语言的内嵌方式来
尝试继承。
1.复用

//采用复用的方式来模拟继承,Pet是父类,Dog是子类
package test
import (
	"fmt"
	"testing"
)

type Pet struct {
}

func (p *Pet) Speak() {
	fmt.Println("...")
}

func (p *Pet) SpeakTo(host string) {
	p.Speak()
	fmt.Println(host)
}

type Dog struct {
	p *Pet
}

//模拟继承,那么这里调用父类方法
func (d *Dog) Speak() {
	d.p.Speak()
}

//模拟继承,那么这里调用父类方法
func (d *Dog) SpeakTo(host string) {
	d.p.SpeakTo(host)
}
func TestInhenrit(t *testing.T) {
	d := new(Dog)
	d.SpeakTo("Jack")
}

在这里插入图片描述

//在上面的基础上我们使用重载,将Dog的Speak方法重载来实现,但是结果输出并不是"Wang,还是"..."
//说明复用这个方案没有办法实现继承
package test

import (
	"fmt"
	"testing"
)

type Pet struct {
}

func (p *Pet) Speak() {
	fmt.Println("...")
}

func (p *Pet) SpeakTo(host string) {
	p.Speak()
	fmt.Println(host)
}

type Dog struct {
	p *Pet
}

//模拟继承,那么这里调用父类方法
func (d *Dog) Speak() {
	fmt.Println("Wang")
}

//模拟继承,那么这里调用父类方法
func (d *Dog) SpeakTo(host string) {
	d.p.SpeakTo(host)
}
func TestInhenrit(t *testing.T) {
	d := new(Dog)
	d.SpeakTo("Jack")
}

在这里插入图片描述
2.内嵌

package test
//内嵌方法:我们没有写Dog的方法,就可以直接调用对于的Pet的方法了,这雨复用是不同的
import (
	"fmt"
	"testing"
)

type Pet struct {
}

func (p *Pet) Speak() {
	fmt.Println("...")
}

func (p *Pet) SpeakTo(host string) {
	p.Speak()
	fmt.Println(host)
}

type Dog struct {
	Pet//内嵌方法,我们只需要写一个类型在这就可以了
}

func TestInhenrit(t *testing.T) {
	d := new(Dog)
	d.SpeakTo("Jack")
}

在这里插入图片描述
下面我们重载方法看看:

//然而重写Pet方法结果依然还是没有改变
package test

import (
	"fmt"
	"testing"
)

type Pet struct {
}

func (p *Pet) Speak() {
	fmt.Println("...")
}

func (p *Pet) SpeakTo(host string) {
	p.Speak()
	fmt.Println(host)
}

type Dog struct {
	Pet
}

//方法重写
func (d *Dog) Speak() {
	fmt.Println("Wang")
}
func TestInhenrit(t *testing.T) {
	//var d *Pet = new(Dog),这一句会报错
	//var d *Pet = *Pet(new(Dog)),强制转换也会报错
	//通过打印结果以及这两句话的错误可以断定内嵌方法也无法完成继承
	d := new(Dog)
	d.SpeakTo("Jack")
}

在这里插入图片描述
从以上的手段我们可以看到Go语言是不支持继承的。

五.多态

package test

import (
	"fmt"
	"testing"
)

type Programmer interface {
	WriteHelloWorld() string
}

type GoProgrammer struct {
}

type JavaProgrammer struct {
}

func (g *GoProgrammer) WriteHelloWorld() string {
	return "I am Go"
}

func (j *JavaProgrammer) WriteHelloWorld() string {
	return "I am Java"
}
//接口接收指针类型
func testMulti(p Programmer) {
	fmt.Printf("%T %s\n", p, p.WriteHelloWorld())
}

func TestClient(t *testing.T) {
	g := new(GoProgrammer)
	j := new(JavaProgrammer)
	testMulti(g)
	testMulti(j)
}

六.空接口与断言

package test

import (
	"fmt"
	"testing"
)

//p是空接口,它类似与c/c++中的void*,可以接受任意类型
func testType(p interface{}) {
	//我们可以使用断言判断传入的空接口的类型
	//v代表结果返回值,ok是bool类型,根据ok判断是否转换成功
	if v, ok := p.(int); ok {
		fmt.Printf("%d: Integer Type\n", v)
		return
	}
	if v, ok := p.(string); ok {
		fmt.Printf("%s: tring Type\n", v)
		return
	}
	fmt.Println("Unkown Type")
}
func TestClient(t *testing.T) {
	testType(1)
	testType("a")
}


当然上面的写法比较重复,下面写法逻辑结构更加清晰与明确

package test

import (
	"fmt"
	"testing"
)

func testType(p interface{}) {
	switch v := p.(type) {
	case int:
		fmt.Println("int", v)
	case string:
		fmt.Println("string", v)
	default:
		fmt.Println("Unkown")
	}
	fmt.Println("Unkown Type")
}
func TestClient(t *testing.T) {
	testType(1)
	testType("a")
}

最后我们总结一下Go接口编写实践的一些建议

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值