一尘不染

了解Go中的多态性

go

我想我一直在考虑针对以下问题的多态解决方案:

假设我有一个BaseTX structwith字段用于交易。现在,我有两种特殊的交易类型:RewardTX structAllowanceTX struct

RewardTX struct目前只有的组成BaseTX struct

AllowanceTX structBaseTX 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在我当前的实现中看不到。

也许我在这里有些脑力衰竭-我真的很想以“正确的行进方式”实现这一目标。:)


阅读 238

收藏
2020-07-02

共1个答案

一尘不染

Go不是面向对象的。 多态性围棋的形式是接口。

来自其他面向对象的语言可能很困难,因为您必须摆脱可能要继承的许多想法,例如“基础”类/类型。只需从设计思想中删除“基础”即可;您正在尝试将合成转换为继承,这只会使您陷入麻烦。

在这种情况下,也许您在这里有合理的构图理由;您有一些通用的共享字段供多种类型使用,但这不是“基本”类型。可能是“元数据”之类的东西-
考虑到您的示例非常抽象,我不能说该怎么称呼,但是您知道了。

所以也许您有:

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嵌入它的结构的调用。

这里的关键是要考虑要 限制在该类型 上的类型的行为(方法),而不是将其视为能够对“子类型”进行操作。子类型不存在,并且 嵌入
在其他类型中的类型也无法在其容器上进行操作。

2020-07-02