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

psa*_*paz 6 go

下面您可以找到三种不同的方法来调用客户结构的方法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())
}
Run Code Online (Sandbox Code Playgroud)

产量

John
John
John
Run Code Online (Sandbox Code Playgroud)

customer1.go(导出Customer struct和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
}
Run Code Online (Sandbox Code Playgroud)

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
}
Run Code Online (Sandbox Code Playgroud)

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
}
Run Code Online (Sandbox Code Playgroud)

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

看来customer3方法是正式的劝阻(//不要做!!!),你可以在这里阅读https://github.com/golang/go/wiki/CodeReviewComments#interfaces

eug*_*ioy 6

Go工作中的接口(和使用的)有点不同,如果你来自Java等其他语言,你会有所期待.

在Go中,实现接口的对象不需要明确地说它实现它.

这具有微妙的后果,例如,即使实施方面没有打扰(或考虑)首先创建接口,类型的消费者也能够与实现分离.

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

您的定义customer1.go与您完全一样(因此类型的实现尽可能简单).

然后,如果有必要,您可以main通过在那里定义接口来解析消费者(在这种情况下是您的包):

type Customer interface {
    Name() string
}

func main() {

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

}
Run Code Online (Sandbox Code Playgroud)

这样,您的main实现可以使用任何具有Name()方法的类型,即使首先实现该类型的包没有考虑到该需求.

为了实现可扩展性,这通常也适用于导出接收参数的函数.

如果要导出这样的函数:

func PrintName(customer Customer) {
    fmt.Println(customer.Name())
}
Run Code Online (Sandbox Code Playgroud)

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