go - 从 golang 包中导出接口而不是结构
问题描述
您可以在下面找到调用客户结构的方法 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
}
我的问题是您会推荐哪种方法,为什么?在可扩展性和可维护性方面哪个更好?您会在大型项目中使用哪一个?
似乎正式不鼓励使用 customer3 方法(// 不要这样做!!!),您可以在此处阅读https://github.com/golang/go/wiki/CodeReviewComments#interfaces
解决方案
如果您来自其他语言(例如 Java),Go 中的接口的工作(和使用)与您所期望的略有不同。
在 Go 中,实现接口的对象不需要明确地说它实现了它。
这会产生微妙的影响,例如,即使实现方一开始并没有打扰(或考虑)创建接口,类型的使用者也能够与实现分离。
因此,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
(例如,您的任何实现都可以工作)。
推荐阅读
- spring-mvc - 在 Spring Boot 应用程序中使用 JSP 和 Thymeleaf 视图
- java - 用于查找两个字符串之间的最短路径的数据结构
- java - 按 n 小时的数据包分组
- python - 从linkedin添加连接的Python脚本
- c - 在 c 中捕获 ctrl-c 并继续执行
- python - pyzmail:使用循环变量获取单个原始消息
- encryption - 如何在我的代码中解决此范围错误?
- javascript - 将数组的字符串表示形式转换为 JS 数组
- ruby-on-rails - 我应该自己从文件系统中删除上传的文件吗?
- c - 将 char** 转换为 char* - 它会改变它指向的内容吗?