dougou7782 2019-05-30 01:11
浏览 206
已采纳

避免在Go中编写过多的getter和setter

I am implementing a message passing system in Go. So I have a general interface called Msg. The Msg interface defines many common fields such as source, destination, send time, receive time, etc. I cannot define a full list of Msgs since I want the library users to define the concrete type of Msgs.

To provide a concrete type of Msg, a user would need to implement a large list of getters and setters, which is very annoying.

One solution I tried is to provide a simple base class like MsgBase and defines all the common properties and getters and setters. And for each concrete type of Msg, I embed a pointer to the MsgBase. This solution works.

But then, I want to embed a value version of the MsgBase in the concrete Msg types. This is because such Msgs are created too many times in the execution and dynamically allocating a MsgBase would increase the garbage collection overhead. I really want all the Msgs are allocated statically since they are passed by the components and should never be shared. If I use the value version of the MsgBase, I cannot use the setters defined in the MsgBase.

I wonder if there is any simple solution to this problem?

EDIT: Adding sample code


type Msg interface {
    // Agent is another interface
    Src() Agent
    SetSrc(a Agent)
    Dst() Agent
    SetDst(a Agent)

    ... // A large number of properties
}

type MsgBase struct {
    src, dst Agent
    ... // Properties as private fields.
}

func (m MsgBase) Src() Agent {
    return m.src
}

func (m *MsgBase) SetSrc(a Agent) {
    m.src = a
}

... // Many other setters and getters for MsgBase


type SampleMsg struct {
    MsgBase // option1
    *MsgBase // option2
}

  • 写回答

1条回答 默认 最新

  • dsriya5471 2019-05-30 11:06
    关注

    Remember that Go doesn't have object-oriented inheritance in the same way Java does. This sounds like you're trying to write an abstract base class that encapsulates all of the parts of a "message"; that's not really typical Go style.

    The fields you're describing are typical message metadata. You can encapsulate this metadata in a pure-data structure. It doesn't necessarily need any behavior, and it doesn't necessarily need getter and setter methods.

    type MessageMeta struct {
      Source Agent
      Destination Agent
    }
    

    The more object-oriented approach is to say a message has a (mutable) metadata block and a (immutable, encoded) payload.

    import "encoding"
    
    type Message interface {
      encoding.BinaryMarshaler // requires MarshalBinary()
      Meta() *MessageMeta
    }
    
    type SomeMessage struct {
      MessageMeta
      Greeting string
    }
    
    func (m *SomeMessage) Meta() *MessageMeta {
      return &m.MessageMeta
    }
    
    func (m *SomeMessage) MarshalBinary() ([]byte, error) {
      return []byte(m.Greeting), nil
    }
    

    A more procedural approach that passes these two things separately is also reasonable. In this case there's no interface for what's a "message", you just pass on the encoded payload; standard-library interfaces like encoding.BinaryMarshaler could make sense here. You might include this in a lower-level interface that's part of your library.

    func Deliver(meta *MessageMeta, payload []byte) error { ... }
    

    Translating one to the other is easy

    func DeliverMessage(m Message) error {
      payload, err := m.Payload()
      if err != nil {
        return err
      }
      meta := m.Meta()
      return Deliver(meta, payload)
    }
    

    If one of the metadata fields is "delivered at", making sure to pass a pointer to the metadata object all the way through the chain lets you update that field in the original object.

    I would not worry about garbage collection as a first-class consideration, except to avoid being overtly wasteful, and to check up on object allocation if GC starts showing up in profiles. Creating two objects instead of one probably isn't going to be a huge problem here.

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

报告相同问题?

悬赏问题

  • ¥20 sub地址DHCP问题
  • ¥15 delta降尺度计算的一些细节,有偿
  • ¥15 Arduino红外遥控代码有问题
  • ¥15 数值计算离散正交多项式
  • ¥30 数值计算均差系数编程
  • ¥15 redis-full-check比较 两个集群的数据出错
  • ¥15 Matlab编程问题
  • ¥15 训练的多模态特征融合模型准确度很低怎么办
  • ¥15 kylin启动报错log4j类冲突
  • ¥15 超声波模块测距控制点灯,灯的闪烁很不稳定,经过调试发现测的距离偏大