首页 > 解决方案 > 理解 Go 中的多态性

问题描述

我想我陷入了思考以下问题的多态性解决方案:

假设我有BaseTX struct一个交易字段。现在我有两种特殊类型的交易: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在我当前的实现中没有看到。

也许我在这里有些脑残——我真的很想以“正确的 Go 方式”来实现它。:)

标签: oopgopolymorphism

解决方案


Go 不是面向对象的。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嵌入它的结构调用。

这里的关键是将类型上的行为(方法)考虑到该类型,而不是认为它能够以某种方式对“子类型”进行操作。子类型不存在,并且嵌入在另一种类型中的类型无法对其容器进行操作。


推荐阅读