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.

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

报告相同问题?

悬赏问题

  • ¥15 VFP如何使用阿里TTS实现文字转语音?
  • ¥100 需要跳转番茄畅听app的adb命令
  • ¥50 寻找一位有逆向游戏盾sdk 应用程序经验的技术
  • ¥15 请问有用MZmine处理 “Waters SYNAPT G2-Si QTOF质谱仪在MSE模式下采集的非靶向数据” 的分析教程吗
  • ¥50 opencv4nodejs 如何安装
  • ¥15 adb push异常 adb: error: 1409-byte write failed: Invalid argument
  • ¥15 nginx反向代理获取ip,java获取真实ip
  • ¥15 eda:门禁系统设计
  • ¥50 如何使用js去调用vscode-js-debugger的方法去调试网页
  • ¥15 376.1电表主站通信协议下发指令全被否认问题