了解Go中的多态性 [英] Understanding polymorphism in Go
问题描述
我想我一直在考虑针对以下问题的多态解决方案:
假设我有一个BaseTX struct
,其中包含用于交易的字段.现在,我有两种特殊类型的事务:RewardTX struct
和AllowanceTX struct
.
RewardTX struct
目前只有BaseTX struct
的组成.
AllowanceTX struct
由BaseTX struct
和AddField
组成.
我还有一个函数logicAndSaveTX()
,它对BaseTX
中的字段具有一些逻辑,但是最后是使用json.Marshal()
序列化整个对象并将byte[]
保存在某个地方.
type TXapi interface {
logicAndSaveTX()
}
type BaseTX struct {
Field1 string
Field2 string
}
type RewardTX struct {
BaseTX
}
type AllowanceTX struct {
BaseTX
AddField string
}
func (tx BaseTX) logicAndSaveTX() {
// logic on BaseTX fields; simplified:
tx.Field1 = "overwritten"
tx.Field2 = "logic done"
// here would be marshal to json and save; simplified to print object:
fmt.Printf("saved this object: %+v \n", tx)
}
func SaveTX(tx TXapi) {
tx.logicAndSaveTX()
}
func main() {
rewardTX := RewardTX{BaseTX : BaseTX{Field1: "Base info1", Field2: "Base info2"}}
SaveTX(rewardTX) // should print rewardTX with fields from BaseTX
allowanceTX := AllowanceTX{BaseTX : BaseTX{Field1: "Base info1", Field2: "Base info2"}, AddField: "additional field"}
SaveTX(allowanceTX) // would like to print allowanceTX with fields from BaseTX + AdditionalField >>> instead only printing fields from BaseTX
}
https://play.golang.org/p/0Vu_YXktRIk
我试图弄清楚如何实现在两种事务上的结构和功能,但是最后正确地序列化了这两种结构.我的问题是,在当前的实现中没有看到AddField
.
也许我在这里有些头脑失败-我真的很想以正确的执行方式"实现这一目标. :)
Go不是面向对象的. Go中多态的 only 形式是接口.>
从其他面向对象的语言中来可能会很困难,因为您必须摆脱可能要继承的许多想法,例如基础"类/类型.只需从您的设计思路中删除基础"即可;您正在尝试将合成转换为继承,这只会使您陷入麻烦.
在这种情况下,也许您在这里有合理的构图理由;您有一些通用的共享字段供多种类型使用,但这不是基本"类型.可能是元数据"之类的东西-考虑到您的示例非常抽象,我不能说该怎么称呼,但是您知道了.
所以也许你有
type TXapi interface {
logicAndSaveTX()
}
type Metadata struct {
Field1 string
Field2 string
}
type RewardTX struct {
Metadata
}
func (tx RewardTX) logicAndSaveTX() {
// logic on BaseTX fields; simplified:
tx.Field1 = "overwritten"
tx.Field2 = "logic done"
// here would be marshal to json and save; simplified to print object:
fmt.Printf("saved this object: %+v \n", tx)
}
type AllowanceTX struct {
Metadata
AddField string
}
func (tx AllowanceTX) logicAndSaveTX() {
// logic on BaseTX fields; simplified:
tx.Field1 = "overwritten"
tx.Field2 = "logic done"
tx.AddField = "more stuff"
// here would be marshal to json and save; simplified to print object:
fmt.Printf("saved this object: %+v \n", tx)
}
如果元数据(或其他任何内容)字段的处理在所有用途中都是相同的,也许您可以给该类型使用其自己的logicTX
方法来填充这些字段,嵌入的结构体的logicAndSaveTX
可以调用该方法它.
这里的关键是考虑要被限定在该类型上的行为(方法),而不是将其视为能够对子类型"进行操作.子类型不存在,并且嵌入的类型无法在其容器上进行操作.
I guess I got stuck in thinking about a polymorphism solution to my following problem:
Let's say I have a BaseTX struct
with fields for a transaction. Now I have two special types of transactions: RewardTX struct
and AllowanceTX struct
.
RewardTX struct
has at this moment only the composition of BaseTX struct
.
AllowanceTX struct
has a composition of BaseTX struct
and an AddField
.
I have also a function logicAndSaveTX()
, which has some logic on fields from BaseTX
but at the end is serializing the whole object using json.Marshal()
and saving the byte[]
somewhere.
type TXapi interface {
logicAndSaveTX()
}
type BaseTX struct {
Field1 string
Field2 string
}
type RewardTX struct {
BaseTX
}
type AllowanceTX struct {
BaseTX
AddField string
}
func (tx BaseTX) logicAndSaveTX() {
// logic on BaseTX fields; simplified:
tx.Field1 = "overwritten"
tx.Field2 = "logic done"
// here would be marshal to json and save; simplified to print object:
fmt.Printf("saved this object: %+v \n", tx)
}
func SaveTX(tx TXapi) {
tx.logicAndSaveTX()
}
func main() {
rewardTX := RewardTX{BaseTX : BaseTX{Field1: "Base info1", Field2: "Base info2"}}
SaveTX(rewardTX) // should print rewardTX with fields from BaseTX
allowanceTX := AllowanceTX{BaseTX : BaseTX{Field1: "Base info1", Field2: "Base info2"}, AddField: "additional field"}
SaveTX(allowanceTX) // would like to print allowanceTX with fields from BaseTX + AdditionalField >>> instead only printing fields from BaseTX
}
https://play.golang.org/p/0Vu_YXktRIk
I try to figure out how to implement the structures and the function to operate on both kinds of transactions but at the end serializing both structures properly. My problem is, that the AddField
is not being seen in my current implementation.
Maybe I have got some brain fail here--I would really like to implement this the "proper Go way". :)
Go is not object-oriented. The only form of polymorphism in Go is interfaces.
Coming from other, object-oriented languages can be difficult, because you have to get rid of a lot of ideas you might try to carry over - things like, for example, "base" classes/types. Just remove "base" from your design thinking; you're trying to turn composition into inheritance, and that's only going to get you into trouble.
In this case, maybe you have a legitimate case for composition here; you have some common shared fields used by multiple types, but it's not a "base" type. It's maybe "metadata" or something - I can't say what to call it given that your example is pretty abstract, but you get the idea.
So maybe you have:
type TXapi interface {
logicAndSaveTX()
}
type Metadata struct {
Field1 string
Field2 string
}
type RewardTX struct {
Metadata
}
func (tx RewardTX) logicAndSaveTX() {
// logic on BaseTX fields; simplified:
tx.Field1 = "overwritten"
tx.Field2 = "logic done"
// here would be marshal to json and save; simplified to print object:
fmt.Printf("saved this object: %+v \n", tx)
}
type AllowanceTX struct {
Metadata
AddField string
}
func (tx AllowanceTX) logicAndSaveTX() {
// logic on BaseTX fields; simplified:
tx.Field1 = "overwritten"
tx.Field2 = "logic done"
tx.AddField = "more stuff"
// here would be marshal to json and save; simplified to print object:
fmt.Printf("saved this object: %+v \n", tx)
}
If the handling of the metadata (or whatever) fields is identical in all uses, maybe you give that type its own logicTX
method to fill those fields, which can be called by the logicAndSaveTX
of the structs that embed it.
The key here is to think of the behavior (methods) on a type to be scoped to that type, instead of thinking of it as somehow being able to operate on "child types". Child types don't exist, and there is no way for a type that is embedded in another type to operate on its container.
这篇关于了解Go中的多态性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!