1. 接口:

  简单说接口就是包含一组方法的集合,这些方法描述了一类对象的行为特征。

  1)比如接口中的方法是 fly() ,描述了鸟类的一个行为特征。

  2)比如接口中的方法是sing(),描述了人类的一个行为特征。

2.接口的好处

从上面的介绍应该可以看出来,鸟类无论是麻雀、鹰、鸽子等都可以实现fly()这个方法,人类中无论中国人、美国人、英国人等都可以实现sing()这个方法。现在还不能看出来它有什么作用?接口也是一种数据类型,只要某个对象实现了接口中的方法,那么接口数据类型的变量就可存储这个对象,而不管这个对象到底是什么。也不管这个对象是如何实现这个方法的。那么就可以利用这个接口来统一调用各个对象。

3.接口的定义 

type    interface_name interface{   //interface_name 接口的名字
  method_name(parameter_list) return_vlaue_list   //方法的名字(参数列表) 返回值列表  (前面有介绍方法的介绍)
  method_name(parameter_list) return_vlaue_list
  ...
}

4. 接口的实现和实现该接口对象之间的联系

  1)不需要显示 的申明。一个对象只要全部实现了一个接口中的全部方法,那么这个对象就实现了这个接口。

  2)一个对象可以实现多个接口。

  3)对象和接口之间是解耦的

5.接口的类型

接口是一个引用类型 

package main
import (
	// "fmt"
)
type Animal interface {
	bark(name string)
}
func main(){
	var d Animal
	d.bark("xiao huang")
}
//运行结果:
panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xc0000005 code=0x0 addr=0x20 pc=0x450199]

goroutine 1 [running]:
main.main()
        E:/go/src/day6/lianxi/main.go:10 +0x29
exit status 2

6.事例

现在就用事例来说明上面的介绍,也能更好 的理解一下。

1)接口变量存储实现接口的对象 和 统一调用对象的示例

package main

import (
	"fmt"
)

type Animal interface {  //定义一个接口,接口中包含两个方法
	Talk()
	Eat()
}
type Dog struct {      //构造一个结构体类型
	name string
}
type Cat struct {      //构造一个结构体类型
	name string
}

func (d *Dog) Talk() {   //Dog结构的方法
	fmt.Printf("%s is wa wa wa!\n", d.name)
}
func (c *Cat) Talk() {   //Cat结构体的方法
	fmt.Printf("%s is miao miao miao\n", c.name)
}
func (c *Cat) Eat() {    //Cat结构体的方法
	fmt.Printf("%s like eat fish\n", c.name)
}
func (d *Dog) Eat() {   //Dog结构体的方法
	fmt.Printf("%s like eat meat\n", d.name)
} 

//上面可以看出Cat Dog都实现了 Animal这个接口,因为它们都实现了接口中的方法
func testAnimalinterface() {
	d1 := &Dog{
		name: "京巴",  //初始一个变量,生成一个对象
	}
	c1 := &Cat{
		name: "maio maio",
	}
	var a Animal          //申明一个Animal接口类型的变量a
	a = d1               //存储 变量d1
	a.Eat()               //可以查看下面的运行结果,说明了变量a 可以存储任何实现这个接口的对象
	a.Talk()
	a = c1
	a.Eat()
	a.Talk()
}
func testsliceAnimalinterface() {
	// var s1 []Animal
	s1 := make([]Animal, 20)    //s1 是一个切片,切片的类型是Animal
	d1 := &Dog{
		name: "京巴",          //生成实例
	}
	// s1 = append(s1, d1)
	s1[0] = d1                  //存储到切片
	d2 := &Dog{
		name: "哈巴",
	}
	// s1 = append(s1, d2)
	s1[1] = d2
	c1 := &Cat{
		name: "maio maio",
	}
	// s1 = append(s1, c1)
	s1[2] = c1
	c2 := &Cat{
		name: "猫黄",
	}
	// s1 = append(s1, c2)
	s1[3] = c2
	fmt.Printf("%#v\n", s1)
	// for _, v := range s1 {
	// 	v.Talk()
	// 	v.Eat()
	// }
	for i := 0; i < 4; i++ {     //遍历切片,调用每个对象的方法
		s1[i].Talk()
		s1[i].Eat()
	}
}
func main() {
	testAnimalinterface()
	 testsliceAnimalinterface()
}
//testAnimalinterface() 运行结果
京巴 like eat meat
京巴 is wa wa wa!
maio maio like eat fish
maio maio is miao miao miao
// testsliceAnimalinterface()运行的结果
京巴 is wa wa wa!
京巴 like eat meat
哈巴 is wa wa wa!
哈巴 like eat meat
maio maio is miao miao miao
maio maio like eat fish
猫黄 is miao miao miao
猫黄 like eat fish

2)支付事例

    定义一个 支付接口

    实现支付接口的支付方式(wechatpay)

    实现支付接口的支付方式(alipay)

    手机开通支付方式

支付接口定义:

package main
type Pay interface{
	pay(user_id string, money float32) error
}

wechatpay

package main
import(
	"fmt"
)
type Wechat struct{
	
}
func (w *Wechat) pay(user_id string, money float32) error{  //实现Pay接口
	fmt.Println("1. 连接到微信支付的服务器")              //假设是这样实现的
	fmt.Println("2. 找到对应的用户")
	fmt.Println("3. 检查余额是否充足")
	fmt.Println("4. 扣钱")
	fmt.Println("5. 返回支付是否成功")
	return nil
}

alipay

package main
import(
	"fmt"
)
type Ali struct{
	
}
func (w *Ali) pay(user_id string, money float32) error{   
	fmt.Println("1. 连接到支付宝的服务器")
	fmt.Println("2. 找到对应的用户")
	fmt.Println("3. 检查余额是否充足")
	fmt.Println("4. 扣钱")
	fmt.Println("5. 返回支付是否成功")
	return nil
}

手机开通支付

package main

import (
	"fmt"
)

type Phone struct {
	PayMap map[string]Pay         //定义一个map,string是支付方式,vlaue是Pay接口类型的
}

func (p *Phone) OpenWechatPay() {     //开通支付方式
	Wechat := &Wechat{}           //实例化一个Wechat类型的对象
	p.PayMap["wechat"] = Wechat   //存储到map,Wechat类型的对象实现了Pay接口,所以可以存储Wechat类型
}
func (p *Phone) OpenAliPay() {
	Ali := &Ali{}
	p.PayMap["ali"] = Ali
}
//抽象上面两个函数
//func (p *Phone) OpenPay(name string, pay Pay) {
	 //  p.PayMap[name] = pay
//}
// func (p *Phone) PayMoney(name string, money float32) (err error) {  
// 	pay, ok := p.PayMap[name]
// 	if !ok {
// 		err = fmt.Errorf("不支持[%s]支付方式", name)
// 		return
// 	}

// 	err = pay.pay("11112222", money)
// 	return
func (p *Phone) PayMoney(name string, money float32) (err error) {  //定义付钱的方法
	pay, ok := p.PayMap[name]
	if !ok {
		err = fmt.Errorf("不支持[%s]的支付方式", name)
		return
	}
	err = pay.pay("222223333", money)
	return
}

  运行:

package main

import (
	"fmt"
)

func main() {
	phone := &Phone{     //实例化一个phone对象
		PayMap: make(map[string]Pay, 16),  初始化
	}
	// phone.OpenWechatPay()
	phone.OpenAliPay()      //开通支付方式
	err := phone.PayMoney("wechat", 20.32)  //付钱
	if err != nil {  //对付钱的判断
		fmt.Printf("支付失败,失败原因:%v\n", err)
		fmt.Println("请换一种支付方式")
		err = phone.PayMoney("ali", 20.32)
		if err != nil {
			fmt.Printf("支付失败,失败原因:%v\n", err)
			return
		}
	}
	fmt.Println("支付成功,欢迎再次光临!")
}
//运行结果   上面代码没开通wechatPay

支付失败,失败原因:不支持[wechat]的支付方式
请换一种支付方式
1. 连接到支付宝的服务器
2. 找到对应的用户
3. 检查余额是否充足
4. 扣钱
5. 返回支付是否成功
支付成功,欢迎再次光临!