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

包装类型的惯用方法是什么?

包装类型的惯用方法是什么?

Go
临摹微笑 2022-01-04 14:06:04
我想包装goquery.Selection以更方便地获取 HTML 和选择器字符串。要访问 的方法goquery.Selection,我应该Get()在下面的代码中实现一些辅助方法吗?type MySelection goquery.Selection// Without this helper method, I should always use type conversion// to use goquery.Selection's methods.func (s *MySelection) Get() *goquery.Selection {    sel := s.(goquery.Selection)    return sel}func (s *MySelection) HTML() string {    // html, _ := s.Html() <- error    html, _ := s.Get().Html()    return html}func (s *MySelection) String() string {    return fmt.Sprintf("%v#%v.%v",        goquery.NodeName(s.Get()),        s.Get().AttrOr("id", "(undefined)"),        s.Get().AttrOr("class", "(undefined)"))}有没有更好的方法来处理这种情况?
查看完整描述

2 回答

?
ABOUTYOU

TA贡献1812条经验 获得超5个赞

你也可以嵌入


type MySelection struct {

    goquery.Selection

    some payload //if needed

}

并且您将免费获得 MySelection 的 goquery.Selection 方法,并且可以添加或覆盖一些方法。


查看完整回答
反对 回复 2022-01-04
?
守着一只汪

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

嗯,有几种方法可以“处理这个”。但不要说出它的名字Get()它不是惯用的

从最佳实践的角度来看,我建议:

  • 将他们的代码与您的代码分离。

  • 实现反腐败层(包装他们的包的包装器)

造成这种情况的原因很多。但是对于 Go 来说,最好保持简单——这归结为一个问题:你想对你的代码进行单元测试吗?

如果答案是肯定的,那么我永远不会直接使用 3rd 方包。我会用我自己的界面包装他们的包。然后,在我的所有代码中使用(注入)该接口,以便我可以在单元测试中模拟它。

同样有几种模式和观点;但是,我将展示这个允许单元测试的包装器。

goquery_wrapper.go

package mypackage


import (

  "path/to/goquery.Selection"

)


var _mySelector *mySelector // Go stdlib uses underscores for private types


type mySelector interface {

  Html() string

  ...

}


type MySelector struct {

}


func (ms *MySelector) Html() {

  // your custom version

}


// initialize the global var with your wrapper

func init() {

  _mySelector = &MySelector{ ... }

}

foo.go

package mypackage


func Foo() {


  // uses the global var initialized with init()

  data := _mySelector.Html()


  // IoC using D.I. through constructors

  obj := NewSomething(_mySelector)


  // IoC using D.I. through methods

  result := bar.Process(_mySelector, "input data")

}

bar_test.go

package mypackage


import (

  "testing"

)


type mockSelector struct {

  HtmlWasCalled bool

  HtmlReturnsThis string

}


func (ms mockSelector) Html() string {

  ms.HtmlWasCalled = true

  return ms.HtmlReturnsThis

}


func TestBar(t *testing.T) {


  // arrange


  // override your global var

  oldMS := _mySelector

  _mySelector := &mockSelector{

    HtmlReturnsThis: "<b>success</b>",

  }


  // act


  // since foo.Bar is using the global var, it now uses

  // our mock we set above.

  result := foo.Bar("sample input")


  // assert

  if result != expected {

    t.Fail()

  }


  // put it back the way it was

  _mySelector = oldMS

}


func TestFoo(t *testing.T) {


  // arrange

  mock := &mockSelector{

    HtmlReturnsThis: "<b>success</b>",

  }


  // act


  // or, just inject your mock if using IoC

  result := bar.Process(mock, "sample input")


  // assert

  ...


}

这使我不必在单元测试期间处理 3rd 方包的细微差别。效果很好,除非包的 API 很大。然后,我什至质疑为什么我开始使用这个包,如果它那么复杂。


查看完整回答
反对 回复 2022-01-04
  • 2 回答
  • 0 关注
  • 153 浏览
慕课专栏
更多

添加回答

举报

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