我正在用Go做几个web服务器项目,有一个共同的问题我一直在面对。我知道我们可以在Go中用接口和方法实现类似多态性的东西,但是很多时候,我有一个场景,我需要在一些数据持有者结构上实现多态性,这些结构(也许)只是有一些共同的字段,而根本没有方法。
比如考虑一个故事写作平台,每个用户都可以写短篇故事和小说。
type ShortStory struct {
Name string
ID int
Body string
}
type LongStory struct {
Name string
ID int
Chapters []string
}
现在我只想有一个数据层函数,比如说: GetStories()
从数据库中获取用户写的所有故事。
func GetStories(id int) []SOME_TYPE {
...
}
我真的不希望在我的 ShortStory
和 LongStory
结构。我知道我可以添加一个虚拟方法,让他们满足一些。Storier
接口,然后使用该接口作为返回类型。但是由于在数据容器模型上没有我想要的方法,所以仅仅为语言添加一个虚方法来启用一个功能,在我看来是一个糟糕的设计选择。
我也可以让函数返回 []interface{}
但我认为这违背了 "类型化语言 "的整体理念。
另一种方法是有两个独立的 GetShortStories()
和 GetLongStories()
方法,它们返回自己类型的片子。但在某些时候,我最终会想把这两个分片合并成一个,在那里我又需要一个 []interface{}
. 是的,我可以返回一个JSON格式。
{
"short_stories" : [...],
"long_stories" : [...]
}
但我希望我的json是这样的。
[{...}, {...}, {...}]
我不会因为一种语言的限制而改变我的API! And I wouldn't change my APIs because of a language's limits!
我不是Go的专家,所以我是不是漏掉了什么?有没有一个 去吧 的方法,还是Golang这边的语言设计真的很糟糕?
如果你不能用语言的特性来表达你想做的事情,你应该首先尝试改变你的程序结构方式,然后再责怪语言本身。有些概念在围棋中不能表达,但在其他语言中可以很好的表达,有些概念你在其他语言中不能很好的表达,但在围棋中可以。改变你解决问题的方式,才能有效地使用这门语言。
解决问题的一种方法是使用不同类型的结构。
type Story struct {
Name string
ID int
ShortBody string
Chapters []string
}
如果... Chapters
是空的,那么它就是一个短篇小说。
另一种方式。
type Story struct {
Name string
ID int
Content StoryContent
}
type StoryContent interface {
Type() string
}
type ShortStory interface {
StoryContent
Body() string
}
type LongStory interface {
StoryContent
Chapters() []string
}
等。