为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

Go
慕慕森 2023-06-19 17:14:47
我正在 Go 中实现一个消息传递系统。所以我有一个名为Msg. 该Msg接口定义了许多公共字段,例如源、目标、发送时间、接收时间等。我无法定义 s 的完整列表,Msg因为我希望库用户定义Msgs 的具体类型。要提供具体的 类型Msg,用户需要实现大量的 getter 和 setter,这非常烦人。我尝试过的一种解决方案是提供一个简单的基类,MsgBase并定义所有公共属性以及 getter 和 setter。对于 的每个具体类型Msg,我都嵌入了一个指向 的指针MsgBase。该解决方案有效。但是,我想MsgBase在具体Msg类型中嵌入一个值版本。这是因为这样的Msgs 在执行过程中创建了太多次,动态分配 aMsgBase会增加垃圾收集开销。我真的希望所有的Msgs 都是静态分配的,因为它们由组件传递并且永远不应该共享。如果我使用 的值版本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 MsgBasetype SampleMsg struct {    MsgBase // option1    *MsgBase // option2}
查看完整描述

1 回答

?
呼如林

TA贡献1798条经验 获得超3个赞

请记住,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 开始出现在配置文件中时检查对象分配。创建两个对象而不是一个对象在这里可能不会成为一个大问题。


查看完整回答
反对 回复 2023-06-19
  • 1 回答
  • 0 关注
  • 96 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信