Golang接口类型的设计理念

249 阅读4分钟

实现Go的接口是以隐式方式进行的。在Go中,不需要通过指定任何关键字来明确地将一个接口实现为一个具体类型。要在具体类型中实现一个接口,只需提供与接口类型中定义的相同签名的方法。

一个接口类型是用关键字interface来定义的。一个接口定义了一组方法(方法集),但这些方法不包含代码:它们没有被实现(它们是抽象的)。方法集是一个类型为了实现接口而必须拥有的方法列表。另外,一个接口不能包含变量。

一个接口的声明格式是

例子

Interface Type catalog

type catalog interface {
	shipping() float64
	tax() float64
}

接口类型catalog是一个契约,用于在目录中创建各种产品类型。目录接口在其契约中提供了两个行为:运输和税收。


实现一个接口

下面的源代码显示了可配置类型作为接口类型catalog 的一个实现。可配置类型被定义为具有接收方法shipping和tax 的结构。这一事实自动地使可配置类型成为catalog 的一个实现。

例子

package main
import "fmt"

type catalog interface { 
   shipping() float64 
   tax() float64
} 
 
type configurable struct { 
   name string
   price, qty float64   
} 

func (c *configurable) tax() float64{
  return c.price * c.qty * 0.05
}

func (c *configurable) shipping() float64{
  return c.qty * 5
}

func  main() {
  tshirt := configurable{}
  tshirt.price = 250
  tshirt.qty = 2
  fmt.Println("Shipping Charge: ", tshirt.shipping())
  fmt.Println("Tax: ", tshirt.tax())  
}

输出

Shipping Charge: 10
Tax: 25

使用 Go 接口的子类型化

Go 支持在通过接口建立对象的子类型时建立组合(has-a)关系。这可以解释为,可配置、下载、简单类型(以及任何其他实现了运输和税收方法的类型)可以被视为 catalog 的子类型,如下图所示。

Implementing an interface

例子

package main

import "fmt"

type catalog interface { 
   shipping() float64 
   tax() float64
} 
 
type configurable struct { 
   name string
   price, qty float64   
} 

func (c *configurable) tax() float64{
  return c.price * c.qty * 0.05
}

func (c *configurable) shipping() float64{
  return c.qty * 5
}

type download struct{
    name string
    price, qty float64
}

func (d *download) tax() float64{
  return d.price * d.qty * 0.07
}

type simple struct {
  name string
  price, qty float64
}

func (s *simple) tax() float64{
  return s.price * s.qty * 0.03
}

func (s *simple) shipping() float64{
  return s.qty * 3
}

func  main() {
  tshirt := configurable{}
  tshirt.price = 250
  tshirt.qty = 2
  fmt.Println("Configurable Product")
  fmt.Println("Shipping Charge: ", tshirt.shipping())
  fmt.Println("Tax: ", tshirt.tax())  

  mobile := simple{"Samsung S-7",10,25}
  fmt.Println("\nSimple Product")  
  fmt.Println("Shipping Charge: ", mobile.shipping())
  fmt.Println("Tax: ", mobile.tax())  


  book := download{"Python in 24 Hours",19,1}
  fmt.Println("\nDownloadable Product")
  fmt.Println("Tax: ", book.tax())
}

输出

Configurable Product
Shipping Charge: 10
Tax: 25

Simple Product
Shipping Charge: 75
Tax: 7.5

Downloadable Product
Tax: 1.33

多个接口

在GO中,接口的隐含机制允许一次满足多个接口类型。这可以通过将一个给定类型的方法集与每个接口类型的方法相交来实现。让我们重新实现之前的代码。新的接口折扣已经被创建。下图说明了这一点。

Implementing Multiple interfaces

例子

package main

import "fmt"

type catalog interface { 
   shipping() float64 
   tax() float64
} 

type discount interface{
    offer() float64
}
 
type configurable struct { 
   name string
   price, qty float64   
} 

func (c *configurable) tax() float64{
  return c.price * c.qty * 0.05
}

func (c *configurable) shipping() float64{
  return c.qty * 5
}

func (c *configurable) offer() float64{
  return c.price * 0.15
}

type download struct{
    name string
    price, qty float64
}

func (d *download) tax() float64{
  return d.price * d.qty * 0.10
}

type simple struct {
  name string
  price, qty float64
}

func (s *simple) tax() float64{
  return s.price * s.qty * 0.03
}

func (s *simple) shipping() float64{
  return s.qty * 3
}

func (s *simple) offer() float64{
  return s.price * 0.10
}

func  main() {
  tshirt := configurable{}
  tshirt.price = 250
  tshirt.qty = 2
  fmt.Println("Configurable Product")
  fmt.Println("Shipping Charge: ", tshirt.shipping())
  fmt.Println("Tax: ", tshirt.tax())  
  fmt.Println("Discount: ", tshirt.offer())  

  mobile := simple{"Samsung S-7",3000,2}
  fmt.Println("\nSimple Product")  
  fmt.Println(mobile.name)
  fmt.Println("Shipping Charge: ", mobile.shipping())
  fmt.Println("Tax: ", mobile.tax())  
  fmt.Println("Discount: ", mobile.offer())

  book := download{"Python in 24 Hours",50,1}
  fmt.Println("\nDownloadable Product")
  fmt.Println(book.name)
  fmt.Println("Tax: ", book.tax())
}

输出

Configurable Product
Shipping Charge: 10
Tax: 25
Discount: 37.5

Simple Product
Samsung S-7
Shipping Charge: 6
Tax: 180
Discount: 300

Downloadable Product
Python in 24 Hours
Tax: 5

接口嵌入

在GO中,接口类型也支持类型嵌入(类似于结构类型)。这使您可以灵活地以最大限度地重用类型的方式来结构您的类型。
继续以目录为例,声明一个可配置的结构,其中嵌入了折扣和礼品包的类型。在这里你创建了目录接口的更多具体类型。因为类型giftpack和discount是目录接口的实现,所以类型 configurable 也是目录接口的实现。Typediscount和giftpack类型中定义的所有字段和方法在可配置类型中也是可用的。
下面的插图显示了如何组合接口类型,以便 is-a 关系仍然满足代码组件之间的关系。

Implementing Interface embedding

例子


package main
import "fmt"

type discount interface{
    offer() float64
}

type giftpack interface{
    available() string
}

type catalog interface { 
   discount
   giftpack
   shipping() float64 
   tax() float64
}

type configurable struct { 
   name string
   price, qty float64   
} 

func (c *configurable) tax() float64{
  return c.price * c.qty * 0.05
}

func (c *configurable) shipping() float64{
  return c.qty * 5
}

func (c *configurable) offer() float64{
  return c.price * 0.15
}

func (c *configurable) available() string{
    if c.price > 1000{
      return "Gift Pack Available"
    }
    return "Gift Pack not Available"
}

type download struct{
    name string
    price, qty float64
}

func (d *download) tax() float64{
  return d.price * d.qty * 0.10
}

func (d *download) available() string{
    if d.price > 500{
      return "Gift Pack Available"
    }
    return "Gift Pack not Available"
}

type simple struct {
  name string
  price, qty float64
}

func (s *simple) tax() float64{
  return s.price * s.qty * 0.03
}

func (s *simple) shipping() float64{
  return s.qty * 3
}

func (s *simple) offer() float64{
  return s.price * 0.10
}

func  main() {
  tshirt := configurable{}
  tshirt.price = 1550
  tshirt.qty = 2
  fmt.Println("Configurable Product")
  fmt.Println("Shipping Charge: ", tshirt.shipping())
  fmt.Println("Tax: ", tshirt.tax())  
  fmt.Println("Discount: ", tshirt.offer())  
  fmt.Println(tshirt.available())

  mobile := simple{"Samsung S-7",3000,2}
  fmt.Println("\nSimple Product")  
  fmt.Println(mobile.name)
  fmt.Println("Shipping Charge: ", mobile.shipping())
  fmt.Println("Tax: ", mobile.tax())  
  fmt.Println("Discount: ", mobile.offer())  

  book := download{"Python in 24 Hours",50,1}
  fmt.Println("\nDownloadable Product")
  fmt.Println(book.name)
  fmt.Println("Tax: ", book.tax())
  fmt.Println(book.available())
}

输出

Configurable Product
Shipping Charge: 10
Tax: 155
Discount: 232.5
Gift Pack Available

Simple Product
Samsung S-7
Shipping Charge: 6
Tax: 180
Discount: 300

Downloadable Product
Python in 24 Hours
Tax: 5
Gift Pack not Available