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 2020长安杯与连接网探
  • ¥15 关于#matlab#的问题:在模糊控制器中选出线路信息,在simulink中根据线路信息生成速度时间目标曲线(初速度为20m/s,15秒后减为0的速度时间图像)我想问线路信息是什么
  • ¥15 banner广告展示设置多少时间不怎么会消耗用户价值
  • ¥16 mybatis的代理对象无法通过@Autowired装填
  • ¥15 可见光定位matlab仿真
  • ¥15 arduino 四自由度机械臂
  • ¥15 wordpress 产品图片 GIF 没法显示
  • ¥15 求三国群英传pl国战时间的修改方法
  • ¥15 matlab代码代写,需写出详细代码,代价私
  • ¥15 ROS系统搭建请教(跨境电商用途)