在实现Go接口时,如何处理重复性和灵活性



我有一个项目使用这样的结构:

type I interface {
GetName() string
DoSomething()
}
//
// A implements I
//
type A struct {
Name  string
}
func (a *A) GetName() string {
return a.Name
}
func (a *A) DoSomething() {
...do something
}
//
// B implements I
//
type B struct {
Name  string
}
func (b *B) GetName() string {
return b.Name
}
func (b *B) DoSomething() {
...do something
}
func (b *B) DoSomethingElse() {
...do something else
}
//
// Both
//
func UseAorB(T I) {
name := T.GetName()...
}
  1. 在接受接口I的函数中调用时,使用GetName是从结构A或B获取名称字段的最佳方式吗
  2. 我是否每次都必须为要实现接口的每件事重新定义DoSomething?或者,如果DoSomething每次都是一样的,而我只能定义一次,那么有更好的方法可以做到这一点吗
  3. 结构B具有接口未定义的方法(DoSomethingElse(。我是否需要使用反射才能将结构B传递给使用接口I调用DoSomethingElse的函数?或者我应该定义一个包含此方法的新接口吗

我想提高我的代码质量,写一个坚实的库,但我不得不说,我感觉自己在与语言作斗争,让我的生活变得更加困难。

  1. 是的,GetName()是实现的好方法

  2. 如果你有类似的方法实现,你通常可以把它移到一个公共结构中并嵌入:

    type Common struct {}
    func (c Common) DoSomething() {...}
    type A struct {
    Common
    Stuff
    }
    type B struct {
    Common
    Other stuff
    }
    

    上面,AB都有DoSomething方法,并且它们共享实现

  3. 不要使用反射。有两种方式:

    1. 使用类型断言:

      func f(in I) {
      if b, ok:=in.(B); ok {
      // b is of type B, so:
      b.DoSomethingElse()
      }
      }
      
  4. 使用接口并键入断言:

    type DoesSometingElse interface {
    DoSomethingElse()
    }
    func f(in I) {
    if x, ok:=in.(DoesSomethingElse); ok{
    x.DoSomethingElse()
    }
    }
    

如果你觉得自己在与语言作斗争,那么要么你建模错误,要么你不知道用该语言做某事的正确方法。所有语言的做事方式都有好的和坏的,而且很多时候每种语言的做法都不一样。如果你是从另一种语言来围棋的,你应该首先停止尝试用另一种语文思考,翻译成围棋,并尝试单独使用围棋。

最新更新