接口是一种存在于具体实现与预期实现之间的约定,接口定义了某一种函数或者方法应该怎么执行,需要接收什么样的参数,返回什么样儿的结果,而由各种不同的函数或者方法去做具体的实现,每一个实现同一个接口的函数则不需要做完全一样的处理。

以我们的生活来做一个比法,买东西付钱这是一个接口,但是具体去实现这个接口的人,则有可能会出现各种各样不同的实现方式,比如我刷卡支付,而你却是现金支付,还可能有一个他使用的是银行汇款,但是不管使用的是什么方式,我们都实现了买东西付钱这个接口。

在软件中,接口遵循与我们生活中的这种现像类似的模式,本文我将介绍在Go中如何有别于其它的如 C/C++、Java等面向对象的编程语言不一样的方法来实现接口。Go的接口的实现虽然与其它你所熟悉的语言有很大的不同,但是它工作得却非常的好。

我们的示例的需求是求各种各样形状的面积,比如矩形/方形/圆等等,因为形状可以做为一个接口,它只是一个抽象的概念,而实际形状,则是形状接口的不同实现,我们我们就可以获得一个统一的获取不同形状的面积的方法。如果你还没有任何编程经验,那可能到现在为止对接口的理解可能还是有一些模糊,但是你应该要知道接口是一种十分强大的编程思想——想想,在全世界都有同样的一个需求的时候,我们定义了一个统一的接串口,这样,你不管走到哪里都能以同样的方式完成,虽然有可能完成的过程不一样,但是你总是知道给了钱就可以拿到自己购买的商品,

Go Structs 中的方法Go 中的 Struct——无类实现面向对象编程我们已经有过对长方形面积的求取方式,我们创建了一个名为 Rectangle 的Struct,然后绑定了一个 Area函数到Rectangle 上来求取Rectangle实例的面积。但是代码却没有接口,所以,Area方法只能被 Rectangle使用,现在让我们将其扩展成为接口。

package main
import "fmt"
// Shaper是一个接口,它只有一个函数 Area返回一个int类型的结果
type Shaper interface {
    Area() int
}
type Rectangle struct {
    length, width int
}
// 该 Area 函数工作于 Rectangle 类型,同时与 Shper有同样的定义,现在就称为Rectangle实现了Shaper接口
func (r Rectangle) Area() int {
    return r.length * r.width
}
func main() {
    r := Rectangle{length: 5, width: 3}
    fmt.Println("Rectangle r details are: ", r)
    fmt.Println("Rectangle r's area is: ", r.Area())
    s := Shaper(r)
    fmt.Println("Area of the Shape r is: ", s.Area())
}

输出为:

Rectangle r details are:  {5 3}
Rectangle r's area is:  15
Area of the Shape r is:  15

在如 Java 或者C#这些语言中,一个类型或者类如果需要实现某个接口,需要这样的:

public class Rectangle implements Shaper { // implementation here }

但是在Go中,我们并不需要像上面Java或者C#那样声明一个实现,你可以看到代码中,Shaper接口仅仅只是被定义了,它有一个方法 Area() int*,而 Rectangle 类型也有一个与 Shaper 中 Area 完全一样的方法声明,名称与返回类型以及接收的参数(这里不接收任何参数)都是一样的,所以Go自动的就明白了 Rectangle 实现了 Shaper 接口,所以,你可以将 Rectangle 丢 Shaper ,像这样的: *s := Shaper®,这样使用 *s.Area() 同样也可以得到该形状的面积了。

上面的其实与我们以前写的示例是一样的,现在来增加一个状态 Square :

package main
import "fmt"
// Shaper是一个接口,它只有一个函数 Area返回一个int类型的结果
type Shaper interface {
    Area() int
}
type Rectangle struct {
    length, width int
}
// 该 Area 函数工作于 Rectangle 类型,同时与 Shper有同样的定义,现在就称为Rectangle实现了Shaper接口
func (r Rectangle) Area() int {
    return r.length * r.width
}
type Square struct {
    side int
}
func (sq Square) Area() int {
    return sq.side * sq.side
}
func main() {
    r := Rectangle{length: 5, width: 3}
    fmt.Println("Rectangle r details are: ", r)
    fmt.Println("Rectangle r's area is: ", r.Area())
    s := Shaper(r)
    fmt.Println("Area of the Shape r is: ", s.Area())
    sq := Square{5}
    fmt.Println("Square details is: ", sq)
    fmt.Println("Area of square sq is: ", sq.Area())
    sqs := Shaper(sq)
    fmt.Println("Shaper sqs area is: ", sqs.Area())
}

结果输出为:

Rectangle r details are:  {5 3}
Rectangle r's area is:  15
Area of the Shape r is:  15
Square details is:  {5}
Area of square sq is:  25
Shaper sqs area is:  25

在上面的示例中,Square 与 Rectangle 都实现了 Shaper 接口,虽然 Square 只有一个字段 side,而 Rectangle 有 length 与 width 两个,但是 Shaper 却知道在使用 Square.Area() 时,具体使用哪一种计算方法,下面我们来看一个更简单的输出,因为 Square 与 Rectangle 都实现了 Shaper 接口,所以我们可以将上面程序的 main() 函数修改成为下面这样的:

func main() {
    r := Rectangle{length: 5, width: 3}
    q := Square{side:5}
    shapes := [...]Shaper{r, q}
    fmt.Println("Looping through shapes for area ...")
    for n, _ := range shapes {
        fmt.Printf("Shape detail: %v , and is area is: %dn", shapes[n], shapes[n].Area())
    }
}

它的输出为:

Shape detail: {5 3} , and is area is: 15
Shape detail: {5} , and is area is: 25

标签: none

评论已关闭