【问题标题】:Wrapping multiple implementations in Go在 Go 中包装多个实现
【发布时间】:2018-08-02 14:42:39
【问题描述】:

我有一个应用程序,它具有相同 API 的多个并发实现(例如,一个由 SQL 数据库支持,另一个由存储在 XML 文件中的数据集支持)。我真正想做的是为 API 中的每种类型的事物定义一个父类型

  1. 保存所有实现通用的成员变量,并且

  2. 定义了所有实现必须具有的方法。

所以,在(无效的)Go 中,我想做类似的事情:

type Person interface {
    Name string
    Title string
    Position string
    Boss() *Person
}

type Person_XML struct {
    Person
}

func (p *Person_XML) Boss() (*Person, error) {
    // Poke around an XML document and answer the question
    return boss, nil
}

type Person_SQL {
    Person
}

func (p *Person_SQL) Boss() (*Person, error) {
    // Do a DB query and construct the record for the boss
    return boss, nil
}

但是,当然,这是不合法的,因为只有结构才有成员变量,只有接口才有成员函数。我可以只用这样的接口来做到这一点:

type Person interface {
    Name() string
    Title() string
    Position() string
    Boss() Person
}

type Person_XML struct {
    NameValue string
    TitleValue string
    PositionValue string
    Person
}

func (p *Person_XML) Name() string {
    return p.NameValue
}

func (p *Person_XML) Title() string {
    return p.TitleValue
}

func (p *Person_XML) Position() string {
    return p.PositionValue
}

func (p *Person_XML) Boss() (Person, error) {
    // Poke around an XML document and answer the question
    return boss, nil
}

对于其他实现也是如此。有没有不强迫我将成员变量转换为成员函数的替代方法?这种用例的最佳做法是什么?

【问题讨论】:

    标签: go struct interface dry embedding


    【解决方案1】:

    我们可以应用第一种方法,因为 struct 可以将接口与字段一起嵌入。如果您查看包sort,它使用相同的方法,将接口嵌入到结构中。

    type Interface interface {
        // Len is the number of elements in the collection.
        Len() int
        // Less reports whether the element with
        // index i should sort before the element with index j.
        Less(i, j int) bool
        // Swap swaps the elements with indexes i and j.
        Swap(i, j int)
    }
    
    type reverse struct {
        // This embedded Interface permits Reverse to use the methods of
        // another Interface implementation.
        Interface
    }
    

    所以你的方法是绝对有效的。并且可以使用 struct receiver 轻松实现接口。

    // Less returns the opposite of the embedded implementation's Less method.
    func (r reverse) Less(i, j int) bool {
            return r.Interface.Less(j, i)
    }
    

    【讨论】:

      【解决方案2】:

      最好的做法是提供一个接口:

      type Person interface {
          PersonName() string
          PersonTitle() string
          PersonPosition() string
          Boss() (Person, error)
      }
      

      并且还提供了一个包含公共字段的结构获取它们的方法:

      type BasePerson struct {
          Name     string
          Title    string
          Position string
      }
      
      func (p *BasePerson) PersonName() string     { return p.Name }
      func (p *BasePerson) PersonTitle() string    { return p.Title }
      func (p *BasePerson) PersonPosition() string { return p.Position }
      

      (注意:*BasePerson 本身没有实现Person,因为它没有Boss() 方法。)

      任何嵌入*BasePerson 的类型都会自动提升其方法,因此要实现Person,只需添加Boss() 方法。

      例如:

      type PersonXML struct {
          *BasePerson
      }
      
      func (p *PersonXML) Boss() (Person, error) {
          // Poke around an XML document and answer the question
          var boss *PersonXML
          return boss, nil
      }
      

      *PersonXML 确实实现了Person

      使用示例:

      var p Person
      p = &PersonXML{
          BasePerson: &BasePerson{
              Name:     "Bob",
              Title:    "sysadmin",
              Position: "leader",
          },
      }
      fmt.Println(p.PersonName())
      

      输出(在Go Playground 上试试):

      Bob
      

      要创建PersonSQL 类型,您只需再次添加Boss() 方法,如果您嵌入*BasePerson

      type PersonSQL struct {
          *BasePerson
      }
      
      func (p *PersonSQL) Boss() (Person, error) {
          // Do a DB query and construct the record for the boss
          var boss *PersonSQL
          return boss, nil
      }
      

      *PersonSQL 再次实现了Person

      【讨论】:

      • 啊哈:嵌入。这就是在PersonSQLPersonXML 中使用*BasePerson 的术语,这使得这个例子尽可能简洁。新的 go golang,我不知道这个功能。出色的帖子准确地回答了我的问题。
      猜你喜欢
      • 1970-01-01
      • 2018-07-29
      • 2017-08-31
      • 1970-01-01
      • 1970-01-01
      • 2016-04-08
      • 2020-12-13
      • 2018-04-16
      • 2015-07-27
      相关资源
      最近更新 更多