初识Go语言16-面向接口编程使用【接口的基本概念、接口嵌入、空接口、类型断言、面向接口编程】


面向接口编程

接口的基本概念

  接口是一组行为规范的集合。

type Transporter interface {
    
     //定义接口。通常接口名以er结尾
    //接口里面只定义方法,不定义变量
    move(src string, dest string) (int, error) //方法名 (参数列表) 返回值列表
    whistle(int) int //参数列表和返回值列表里的变量名可以省略
}

  只要结构体拥有接口里声明的所有方法,就称该结构体“实现了接口”。一个struct可以同时实现多个接口。

type Car struct {
    
     //定义结构体时无需要显式声明它要实现什么接口
    price int
}

func (car Car) move(src string, dest string) (int, error) {
    
    
    return car.price, nil
}
func (car Car) whistle(n int) int {
    
    
    return n
}

  接口值有两部分组成, 一个指向该接口的具体类型的指针和另外一个指向该具体类型真实数据的指针。

car := Car{
    
    "宝马", 100}
var transporter Transporter
transporter = car

在这里插入图片描述

接口的使用

func transport(src, dest string, transporter Transporter) error {
    
    
	 _,err := transporter.move(src, dest)
	return err
}
var car Car		//Car实现了Transporter接口
var ship Shiper	// Shiper实现了Transporter接口
transport("北京", "天津", car)
transport("北京", "天津", ship)

接口的赋值

func (car Car) whistle(n int) int {
    
    }//方法接收者是值
func (ship *Shiper) whistle(n int) int {
    
    } //方法接收者用指针,则实现接口的是指针类型
car := Car{
    
    }
ship := Shiper{
    
    }
var transporter Transporter
transporter = car 
transporter = &car     //值实现的方法,指针同样也实现了
transporter = &ship

接口嵌入

type Transporter interface {
    
    
	whistle(int) int
}
type Steamer interface {
    
    
    Transporter //接口嵌入。相当于Transporter接口定义的行为集合是Steamer的子集
    displacement() int
}

空接口

  空接口类型用interface{}表示,注意有{}。

var i interface{
    
    } 

  空接口没有定义任何方法,因此任意类型都实现了空接口。

var a int = 5
i = a
func square(x interface{
    
    }){
    
    } //该函数可以接收任意数据类型

  slice的元素、map的key和value都可以是空接口类型。map中的key可以是任意能够用==操作符比较的类型,不能是函数、map、切片,以及包含上述3中类型成员变量的的struct。map的value可以是任意类型。

类型断言

if v, ok := i.(int); ok {
    
    //若断言成功,则ok为true,v是具体的类型
	fmt.Printf("i是int类型,其值为%d\n", v)
} else {
    
    
	fmt.Println("i不是int类型")
}

  当要判断的类型比较多时,就需要写很多if-else,更好的方法是使用switch i.(type)。

switch v := i.(type) {
    
        //隐式地在每个case中声明了一个变量v
case int:  //v已被转为int类型
	fmt.Printf("ele is int, value is %d\n", v)
	//在 Type Switch 语句的 case 子句中不能使用fallthrough
case float64:      //v已被转为float64类型
	fmt.Printf("ele is float64, value is %f\n", v)
case int8, int32, byte: //如果case后面跟多种type,则v还是interface{}类型
	fmt.Printf("ele is %T, value is %d\n", v, v)
}

面向接口编程

电商推荐流程
在这里插入图片描述

为每一个步骤定义一个接口。

type Recaller interface {
    
    
    Recall(n int) []*common.Product //生成一批推荐候选集
}
type Sorter interface {
    
    
    Sort([]*common.Product) []*common.Product //传入一批商品,返回排序之后的商品
}
type Filter interface {
    
    
    Filter([]*common.Product) []*common.Product //传入一批商品,返回过滤之后的商品
}
type Recommender struct {
    
    
    Recallers []recall.Recaller
    Sorter sort.Sorter
    Filters []filter.Filter
}

使用纯接口编写推荐主流程。

func (rec *Recommender) Rec() []*common.Product {
    
    
	RecallMap := make(map[int]*common.Product, 100)
	//顺序执行多路召回
	for _, recaller := range rec.Recallers {
    
    
		products := recaller.Recall(10) //统一设置每路最多召回10个商品
		for _, product := range products {
    
    
			RecallMap[product.Id] = product //把多路召回的结果放到map里,按Id进行排重
		}
	}
	//把map转成slice
	RecallSlice := make([]*common.Product, 0, len(RecallMap))
	for _, product := range RecallMap {
    
    
		RecallSlice = append(RecallSlice, product)
	}
	SortedResult := rec.Sorter.Sort(RecallSlice) //对召回的结果进行排序
	//顺序执行多种过滤规则
	FilteredResult := SortedResult
	for _, filter := range rec.Filters {
    
    
		FilteredResult = filter.Filter(FilteredResult)
	}
	return FilteredResult
}

  面向接口编程,在框架层面全是接口。具体的实现由不同的开发者去完成,每种实现单独放到一个go文件里,大家的代码互不干扰。通过配置选择采用哪种实现,也方便进行效果对比。

猜你喜欢

转载自blog.csdn.net/m0_52896752/article/details/130361188
今日推荐