2 回答
TA贡献1784条经验 获得超7个赞
Go 的接口隐式实现的概念是不是与第三个通用包的想法相矛盾?
我认为确实如此。Go 作者引入了一个隐式接口实现来消除包之间不必要的依赖关系。这适用于简单的接口,例如io.Reader
,但你不能在任何地方应用它。
语言创建者之一Rob Pike 表示,接口的非声明式满足并不是 Go 中接口背后理念的基本部分。这是一个不错的功能,但并非该语言的所有元素都是实用的或每次都可以使用。
对于复杂的接口,您需要导入定义接口的包。例如,如果您要实现与sql
标准库中的包一起使用的 SQL 驱动程序,则必须导入该sql/driver
包。
我建议不要在项目开始时引入接口。通常,它会导致您需要解决人工问题,例如每次更新对域模型的理解时重写界面。从第一次尝试中很难得出一个好的抽象,而且在我看来,在许多情况下,这是不必要的。
我需要查询产品的外部来源。我不在乎外部源如何存储数据(数据库、文件、网络)。我只需要一个“产品”类型。所以要么我定义一个 Product 类型,强制外部实现导入并使用它,要么 Go 方式 - 定义一个 Product 接口,让实现隐式实现这个接口。这显然不起作用
我在这里看到两个松散相关的目标:
定义一个接口来交换产品源的实现。
实现产品源的包不应导入定义接口的包。
根据我的经验,我建议仅在您至少有一个产品源服务的有效实现时才执行第 1 点。
第2点并不总是可以实现的,这很好;请参阅上面标准 Go 库中的示例。
PS请考虑不创建Product
界面。PorductSource
虽然最终提出接口确实有意义,Product
但很可能只是一组数据;struct
是表示此类信息的完美方式。请参阅这个非常相关的代码示例和这篇文章以获得灵感。
TA贡献1895条经验 获得超7个赞
您的方法的问题是您希望有人实现一个引用您的类型(MyType)的接口。如果没有引用您的类型的实现,这显然无法完成。这是阻止上述代码工作的唯一原因。
如果你摆脱MyType:
type TypeGetter interface {
GetType() interface {
Title() string
Price() int
}
}
和实施:
func (g CustomTypeGetter) GetType() interface {
Title() string
Price() int
} {
return CustomType{"Hello", 42}
}
然后这段代码将起作用:
func main() {
tg := external.CustomTypeGetter{}
mypackage.MyHandler(tg)
}
是的,这需要重复,但这只是因为您不希望未知/未来的实现引用您的类型(不依赖于它)。
在这种情况下,您可以更改MyHandler()为采用类型值MyType(摆脱“工厂”):
func MyHandler(t MyType) {
fmt.Printf("Title: %s, Price: %d", t.Title(), t.Price())
}
MyType并且可以传递任何实现的值。在包中添加一个“工厂” external:
func NewCustomType(title string, price int) CustomType {
return CustomType{
title: title,
price: price,
}
}
并像这样使用它:
func main() {
t := external.NewCustomType("title", 1)
mypackage.MyHandler(t)
}
如果你真的需要工厂模式,那么是的,创建一个可以容纳的第三个包MyType是要走的路。然后你的应用程序和实现都可以引用这个第三个包。
- 2 回答
- 0 关注
- 74 浏览
添加回答
举报