接口interface

1.什么是接口

接口就是一种规范与标准,在生活中经常见接口,例如:笔记本电脑的USB接口,可以将任何厂商生产的鼠标与键盘,与电脑进行链接。为什么呢?原因就是,USB接口将规范和标准制定好后,各个生产厂商可以按照该标准生产鼠标和键盘就可以了。

在程序开发中,接口只是规定了要做哪些事情,干什么。具体怎么做,接口是不管的。这和生活中接口的案例也很相似,例如:USB接口,只是规定了标准,但是不关心具体鼠标与键盘是怎样按照标准生产的.

在企业开发中,如果一个项目比较庞大,那么就需要一个能理清所有业务的架构师来定义一些主要的接口,这些接口告诉开发人员你需要实现那些功能。

2.接口定义

接口定义的语法如下:

方式一:interface接收任意数据格式
//先定义接口  一般以er结尾  根据接口实现功能
type CurrencyEr2 interface{
	Symbol() string
}

方式二:指定类型
type Currency string

怎样具体实现接口中定义的方法呢?

func (c Currency)Symbol() string {
	m := ""
	switch c {
	case "CNY":
		// 人民币
		m = "¥"
	case "KRW":
		// 韩币
		m = "₩"
	case "TWD":
		// 台币
		m = "$"
	case "JPY":
		// 日元
		m = "¥"
	case "USD":
		// 美元
		m = "$"
	}
	return m
}

具体的调用如下:

func main() {
  // 方式一:
  a:=CurrencyEr2(Currency("CNY")).Symbol()
	fmt.Println(a)
  // 方式二:
	b:=Currency("CNY").Symbol()
	fmt.Println(b)
}

只要类(结构体)实现对应的接口,那么根据该类创建的对象,可以赋值给对应的接口类型。

接口的命名习惯以er结尾。

3.多态

接口有什么好处呢?实现多态。

多态就是同一个接口,使用不同的实例而执行不同操作

所谓多态指的是多种表现形式,如下图所示:

使用接口实现多态的方式如下:

package main

import "fmt"

//先定义接口  一般以er结尾  根据接口实现功能
type CurrencyEr2 interface {
	//方法  方法的声明
	Symbol() string
}

type Currency string
type Currency2 string

func (c Currency) Symbol() string {
	m := ""
	switch c {
	case "CNY":
		m = "¥"
	}
	return m
}
func (c Currency2) Symbol() string {
	m := ""
	switch c {
	case "USD":
		m = "$"
	}
	return m
}

//多态的实现
//将接口作为函数参数  实现多态
func Start(c CurrencyEr2) string {
	return c.Symbol()
}

func main() {

	//调用多态函数
	a := Start(Currency("CNY"))
	fmt.Println(a)

	//调用多态函数
	b := Start(Currency2("USD"))
	fmt.Println(b)
}

多态加减计算器

package main

import "fmt"

//定义接口
type Opter interface {
	//方法声明
	Result() int
}

//父类结构体
type Operate struct {
	num1 int
	num2 int
}

//加法子类结构体
type Add struct {
	Operate
}

//实现加法子类的方法
func (a *Add) Result() int {
	return a.num1 + a.num2
}

//减法子类结构体
type Sub struct {
	Operate
}

//实现减法子类的方法
func (s *Sub) Result() int {
	return s.num1 - s.num2
}

//创建一个类负责对象创建
//工厂类
type Factory struct {
}

func (f *Factory) Result(num1 int, num2 int, ch string) int {
	sum := 0
	switch ch {
	case "+":
		var a Add
		a.num1 = num1
		a.num2 = num2
		sum = Opter.Result(&a)
	case "-":
		var s Sub
		s.num1 = num1
		s.num2 = num2
		sum = Opter.Result(&s)
	}
	return sum
}

//通过设计模式调用
func main() {
	//创建工厂对象
	var f Factory
	a:= f.Result(10, 20, "+")
	fmt.Println(a)
}

4.接口继承与转换

接口也可以实现继承:

package main

import "fmt"

//先定义接口  一般以er结尾  根据接口实现功能
type Humaner2 interface {   //子集
    //方法  方法的声明
    sayhi()

}

type Personer interface {  //超集
    Humaner2   //继承sayhi()

    sing(string)
}

type student13 struct {
    name  string
    age   int
    score int
}

func (s *student13)sayhi()  {
    fmt.Printf("大家好,我是%s,今年%d岁,我的成绩%d分\n",s.name,s.age,s.score)
}

func (s *student13)sing(name string)  {
    fmt.Println("我为大家唱首歌",name)
}

func main() {
    //接口类型变量定义
    var h Humaner2
    var stu student13 = student13{"小吴",18,59}
    h = &stu
    h.sayhi()

    //接口类型变量定义
    var p Personer
    p = &stu
    p.sayhi()
    p.sing("大碗面")
}

接口继承后,可以实现“超集”接口转换“子集”接口,代码如下:

package main

import "fmt"

//先定义接口  一般以er结尾  根据接口实现功能
type Humaner2 interface {   //子集
    //方法  方法的声明
    sayhi()

}

type Personer interface {  //超集
    Humaner2   //继承sayhi()

    sing(string)
}

type student13 struct {
    name  string
    age   int
    score int
}

func (s *student13)sayhi()  {
    fmt.Printf("大家好,我是%s,今年%d岁,我的成绩%d分\n",s.name,s.age,s.score)
}

func (s *student13)sing(name string)  {
    fmt.Println("我为大家唱首歌",name)
}

func main()  {
    //接口类型变量定义
    var h Humaner2  //子集
    var p Personer    //超集
    var stu student13 = student13{"小吴",18,59}

    p = &stu
    //将一个接口赋值给另一个接口
    //超集中包含所有子集的方法
    h = p  //ok

    h.sayhi()

    //子集不包含超集
    //不能将子集赋值给超集
    //p = h  //err
    //p.sayhi()
    //p.sing("大碗面")
}

5.空接口

空接口(interface{})不包含任何的方法,正因为如此,所有的类型都实现了空接口,因此空接口可以存储任意类型的数值。

例如:

var i interface{}
//接口类型可以接收任意类型的数据
//fmt.Println(i)
fmt.Printf("%T\n",i)
i = 10
fmt.Println(i)
fmt.Printf("%T\n",i)

当函数可以接受任意的对象实例时,我们会将其声明为interface{},最典型的例子是标准库fmt中PrintXXX系列的函数,例如:

func Printf(fmt string, args ...interface{})
func Println(args ...interface{})

如果自己定义函数,可以如下:

func Test(arg ...interface{}) {

}

Test( )函数可以接收任意个数,任意类型的参数。

6.接口转换

结论:超集可以转换为子集,子集不可以转换为超集

package main

import "fmt"

type Humaner interface { //子集
	sayhi()
}

type Personer interface { //超集
	Humaner //匿名字段,继承了sayhi()
	sing(lrc string)
}

type Student struct {
	name string
	id   int
}

//Student实现了sayhi()
func (tmp *Student) sayhi() {
	fmt.Printf("Student[%s, %d] sayhi\n", tmp.name, tmp.id)
}

func (tmp *Student) sing(lrc string) {
	fmt.Println("Student在唱着:", lrc)
}

func main() {
	//超集可以转换为子集,反过来不可以
	var iPro Personer //超集
	iPro = &Student{"mike", 666}

	var i Humaner //子集

	//iPro = i //err
	i = iPro //可以,超集可以转换为子集
	i.sayhi()

}

7.实现map字典接口

package main

import (
	"fmt"
	"sync"
)


type UserAges struct {
	ages map[string] int
	sync.Mutex
}

func (u *UserAges)Add(name string,age int)  {
	u.Lock()
	defer u.Unlock()
	u.ages[name] = age
}

func (u *UserAges)Get(name string)int{
	if age,ok:=u.ages[name];ok{
		return age
	}
	return -1
}

func main() {
	dic:=make(map[string]int)
	dic["age"] = 18

	r:=UserAges{ages: dic}
	r.Add("jeff",20)

	fmt.Println(r)
	
	age:=r.Get("age")
	fmt.Println(age)
}

8.interface案例

8.1案例1

package main

import "fmt"

type Bike interface {
	save()
	update()
	insert()
}

type User struct {
	name string
}

func (this *User) save() {
	fmt.Println("保存成功", this.name)
}
func (this *User) update() {
	fmt.Println("更新成功", this.name)
}
func (this *User) insert() {
	fmt.Println("插入成功", this.name)
}

func main() {
	var data Bike = &User{name: "jeff"}
	data.save()
	data.update()
	data.insert()
}

8.2案例2

package main

import (
	"fmt"
	"time"
)

type BikeC interface {
	send()
	recv()
}

type Bike struct {
	Id int
	Ch chan int
}

//只写
func (p *Bike) send(ch chan<- int, msg int) {
	ch <- msg
}

//只读
func (p *Bike) recv(ch <-chan int) {
	time.Sleep(time.Second)
	for {
		msg, ok := <-ch
		if ok {
			fmt.Println(msg)
		}
	}
}

func main() {
	c1 := make(chan int, 1)
	bike := Bike{
		Id: 1,
		Ch: c1,
	}
	go bike.send(c1, 1)
	go bike.recv(c1)
	go bike.send(c1, 2)

	time.Sleep(time.Second * 2)
}

posted @ 2020-10-23 17:39  Jeff的技术栈  阅读(168)  评论(0编辑  收藏  举报
回顶部