douzao2590 2018-12-07 17:34
浏览 52
已采纳

了解Go中的多态性

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 
", 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". :)

  • 写回答

1条回答 默认 最新

  • duanpanbo9476 2018-12-07 17:45
    关注

    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 
    ", 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 
    ", 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.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 winform的chart曲线生成时有凸起
  • ¥15 msix packaging tool打包问题
  • ¥15 finalshell节点的搭建代码和那个端口代码教程
  • ¥15 用hfss做微带贴片阵列天线的时候分析设置有问题
  • ¥15 Centos / PETSc / PETGEM
  • ¥15 centos7.9 IPv6端口telnet和端口监控问题
  • ¥20 完全没有学习过GAN,看了CSDN的一篇文章,里面有代码但是完全不知道如何操作
  • ¥15 使用ue5插件narrative时如何切换关卡也保存叙事任务记录
  • ¥20 海浪数据 南海地区海况数据,波浪数据
  • ¥20 软件测试决策法疑问求解答