duanrang2627 2018-06-25 20:07
浏览 130
已采纳

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

Below you can find three different ways of calling a method Name() of a customer struct. The result is exactly the same but each one of the three package exports different things:

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())
}

Output

John
John
John

customer1.go (Export Customer struct and Name() method)

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 (Do not export customer struct. Export only Name() method)

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 (Do not export customer struct. Export Customer Interface)

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
}

My question is which approach you would recommend and why? Which is better in terms of extensibility and maintainability? Which one you would use for a large project?

It seems that customer3 approach is officially discouraged (// DO NOT DO IT!!!) as you can read here https://github.com/golang/go/wiki/CodeReviewComments#interfaces

  • 写回答

1条回答 默认 最新

  • donglei3370 2018-06-25 20:49
    关注

    Interfaces in Go work (and are used) a bit differently that what you'd expect if you come from other languages such as Java.

    In Go, the object implementing the interface does not need to explicitly say it implements it.

    That has subtle ramifications, such as the consumer of a type being able to decouple from the implementation even if the implementing side did not bother (or think about) creating an interface in the first place.

    So, the idiomatic way in Go would be to use a variation of your first approach.

    You'd define customer1.go exactly as you did (so implementation of the type is as simple as possible).

    Then if necessary you can de-couple in the consumer (your main package in this case) by defining an interface there:

    type Customer interface {
        Name() string
    }
    
    func main() {
    
        var c1 Customer
        c1 := customer1.NewCustomer("John")
        fmt.Println(c1.Name())
    
    }
    

    That way, your main implementation can work with any type that has a Name() method, even if the package implementing the type in the first place did not think about that need.

    To achieve extensibility, this is usually also applied for functions you export that receive parameters.

    If you are exporting a function like this:

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

    Then that function can be invoked with any object that implements Customer (any of your implementations would work for example).

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 关于#java#的问题:找一份能快速看完mooc视频的代码
  • ¥15 这种微信登录授权 谁可以做啊
  • ¥15 请问我该如何添加自己的数据去运行蚁群算法代码
  • ¥20 用HslCommunication 连接欧姆龙 plc有时会连接失败。报异常为“未知错误”
  • ¥15 网络设备配置与管理这个该怎么弄
  • ¥20 机器学习能否像多层线性模型一样处理嵌套数据
  • ¥20 西门子S7-Graph,S7-300,梯形图
  • ¥50 用易语言http 访问不了网页
  • ¥50 safari浏览器fetch提交数据后数据丢失问题
  • ¥15 matlab不知道怎么改,求解答!!