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

时间:2019-05-30 01:11:45

标签: go interface garbage-collection getter-setter

我正在Go中实现一个消息传递系统。因此,我有一个称为Msg的常规接口。 Msg界面定义了许多公共字段,例如源,目的地,发送时间,接收时间等。我无法定义Msg的完整列表,因为我希望库用户定义具体的类型。 Msg个。

要提供具体的Msg类型,用户将需要实现大量的getter和setter列表,这很烦人。

我尝试的一种解决方案是提供一个简单的基类,例如MsgBase,并定义所有常见的属性以及getter和setter。对于Msg的每种具体类型,我都嵌入了一个指向MsgBase的指针。此解决方案有效。

但是,我想在具体的MsgBase类型中嵌入Msg的值版本。这是因为这样的Msg在执行中创建了太多次,并且动态分配MsgBase会增加垃圾回收的开销。我真的希望所有Msg都是静态分配的,因为它们是由组件传递的,并且永远不应该共享。如果使用MsgBase的值版本,则不能使用MsgBase中定义的设置器。

我想知道是否有解决此问题的简单方法?

编辑:添加示例代码


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 个答案:

答案 0 :(得分:2)

请记住,Go不像Java一样具有面向对象的继承。听起来您正在尝试编写一个抽象的基类,该基类封装了“消息”的所有部分。那不是真正的Go风格。

您描述的字段是典型的邮件元数据。您可以将此元数据封装在纯数据结构中。它不一定需要任何行为,也不一定需要getter和setter方法。

type MessageMeta struct {
  Source Agent
  Destination Agent
}

更面向对象的方法是说一条消息具有一个(可变的)元数据块和一个(不变的,编码的)有效载荷。

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
}

一种更程序化的方法可以分开传递这两件事也是合理的。在这种情况下,“消息”没有接口,您只需传递编码的有效负载即可。像encoding.BinaryMarshaler这样的标准库接口在这里可能很有意义。您可以将其包含在库的下级界面中。

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

彼此轻松翻译

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

如果其中一个元数据字段是“传递给”的,请确保在整个链中始终将指针传递给元数据对象,以便您可以在原始对象中更新该字段。

我不会担心将垃圾收集作为头等大事,除非避免过度浪费,并且如果GC开始显示在配置文件中,则检查对象分配。在这里创建两个对象而不是一个对象可能不会成为一个大问题。