从golang包中导出接口而不是结构

时间:2018-06-25 20:07:30

标签: go

在下面,您可以找到三种不同的方法来调用客户struct的方法Name()。结果完全相同,但是三个软件包中的每个软件包输出的东西都不相同:

package main

import (
    "customer1"
    "customer2"
    "customer3"
    "fmt"
    "reflect"
)

func main() {

    c1 := customer1.NewCustomer("John")
    fmt.Println(c1.Name())

    c2 := customer2.NewCustomer("John")
    fmt.Println(c2.Name())

    c3 := customer3.NewCustomer("John")
    fmt.Println(c3.Name())
}

输出

John
John
John

customer1.go(导出客户结构和Name()方法)

package customer1

type Customer struct {
    name string
}

func NewCustomer(name string) * Customer{
    return &Customer{name: name}
}

func (c *Customer) Name() string {
    return c.name
}

customer2.go(不导出客户结构。仅导出Name()方法)

package customer2

type customer struct {
    name string
}

func NewCustomer(name string) *customer {
    return &customer{name: name}
}

func (c *customer) Name() string {
    return c.name
}

customer3.go(不导出客户结构。导出客户界面)

package customer3

type Customer interface {
    Name() string
}
type customer struct {
    name string
}

func NewCustomer(name string) Customer {
    return &customer{name: name}
}

func (c *customer) Name() string {
    return c.name
}

我的问题是您会推荐哪种方法,为什么?在可扩展性和可维护性方面哪个更好?您将在大型项目中使用哪一个?

您似乎可以在这里https://github.com/golang/go/wiki/CodeReviewComments#interfaces

似乎不建议使用customer3方法(//不要这样做!!!)

1 个答案:

答案 0 :(得分:6)

Go的接口(和使用的接口)与您来自其他语言(例如Java)的期望有所不同。

在Go中,接口的对象 implementing 无需明确地说它实现了它。

具有细微的影响,例如,即使实施方不理会(或考虑)创建,该类型的 consumer 仍能够与实现分离。一个界面。

因此,Go的惯用方式是使用第一种方法的变体。

您将完全按照定义customer1.go的方式进行操作(因此类型的实现尽可能简单)。

然后如有必要,您可以通过在其中定义一个接口来断开消费者(在这种情况下,您的main包)的耦合:

type Customer interface {
    Name() string
}

func main() {

    var c1 Customer
    c1 := customer1.NewCustomer("John")
    fmt.Println(c1.Name())

}

这样,即使一开始实现该类型的程序包没有考虑到这种需要,您的main实现也可以使用任何具有Name()方法的类型。

为实现可扩展性,通常也将其应用于导出的接收参数的函数。

如果要导出这样的函数:

func PrintName(customer Customer) {
    fmt.Println(customer.Name())
}

然后可以使用实现Customer的任何对象调用该函数(例如,您的任何实现都可以使用)。