减少Golang中的代码重复

时间:2016-07-19 22:20:00

标签: go interface refactoring code-duplication

我无法找到" go-way"解决代码重复问题。这就是问题所在。请考虑以下事项:

type (
  WithKey interface {
    key() string
  }

  SharedFunctionality interface {
    WithKey
    MethodA() string
    MethodB() string
    // ... etc ...
  }

  FirstType struct { ... }
  SecondType struct { ... }
  // ... etc ...
)
func (ft *FirstType) key() string { ... }
func (st *SecondType) key() string { ... }

现在,SharedFunctionality中的方法仅取决于key()方法的结果。我可以像下面这样实现它们:

func runMethodA(k WithKey) string {
  key := k.key()
  // do something and return a string
}
func runMethodB(k WithKey) string {
  key := k.key()
  // do something else and return a string
}

func (ft *FirstType) MethodA() string { return runMethodA(ft) }
func (ft *FirstType) MethodB() string { return runMethodB(ft) }
func (st *SecondType) MethodA() string { return runMethodA(st) }
func (st *SecondType) MethodB() string { return runMethodB(st) }

我不喜欢这种方法是,当我添加更多类型(ThirdType,FourthType等)或者我向SharedFunctionality添加更多方法时,我必须添加大量的样板代码...特别是对于M方法SharedFunctionality和N种类型,我必须拼出M * N单行,如上面的4所示。

要做的事情是:

func (k WithKey) MethodA() string {
  key := k.key()
  // do something
}

换句话说:我喜欢在接口类型上定义方法。含义:实现" WithKey"的所有对象会自动获取MethodA() stringMethodB() string等,因此会自动实现SharedFunctionality界面。类似 Java接口中的默认方法

但是,我知道在接口类型中定义方法是不可能的......

解决这个问题的方法是什么?

我已经看到了一种方法,我将使用接口类型的匿名字段创建一个结构,然后在那里实现这些方法:

type SharedFuncStruct struct {
  WithKey
}
func (sfs *SharedFuncStruct) MethodA() string {
  key := sfs.key()
  // whatever
}
// same for MethodB()

然后使用它,我会做类似的事情:

first := ... getFirstTypeValue()
sfs := &SharedFuncStruct{first}
sfs.MethodA() // etc

看起来它可以工作,但它仍然感觉太多样板代码。

还有其他选择吗?

2 个答案:

答案 0 :(得分:2)

在我看来,你需要提取一个包。我有这个功能的方式是

package keyed

type hasKey interface {
    Key() string
}

func MethodA(k hasKey) string {
    key := k.Key()
    // whatever
}

func MethodB(k hasKey) string {
    key := k.Key()
    // whatever
}

然后

package your_package

import "keyed"

type (
    FirstType struct { ... }
    SecondType struct { ... }
)

func (ft *FirstType) Key() string { ... }
func (st *SecondType) Key() string { ... }

func main() {
    first := &FirstType{}
    second := &SecondType{}
    keyed.MethodA(first)
    keyed.MethodA(second)
    keyed.MethodB(first)
    keyed.MethodB(second)
}

答案 1 :(得分:1)

有趣的事实:您可以将接口嵌入到结构中,然后结构自动实现该接口。您可以使用它来有效地定义接口上的方法:

https://play.golang.org/p/ZufTOzr9ig

type (
    WithKey interface {
        key() string
    }

    SharedFunctionality interface {
        WithKey
        MethodA() string
        MethodB() string
    }

    KeyHolder struct {
        WithKey
    }

    FirstType struct { ... }
    SecondType struct { ... }
)

func (k *KeyHolder) MethodA() string {
    key := k.key()
    // ...
}

func (k *KeyHolder) MethodB() string {
    key := k.key()
    // ...
}

func NewSharedFunctionality(w WithKey) SharedFunctionality {
    return &KeyHolder{w}
}

func (ft *FirstType) key() string { ... }
func (st *SecondType) key() string { ... }

在这种情况下,KeyHolder结构嵌入了WithKey接口,因此可以容纳任何具有key() string方法的内容(FirstType和{{1}有)。然后,您可以在该结构上定义SecondTypeMethodA,然后该结构将同时满足MethodB接口(因为它嵌入它)和WithKey接口,使用任何密钥由嵌入式SharedFunctionality返回。

换句话说,不是将WithKey包裹在FirstType中,而是放在WithKey中(意味着SharedFunctionality本身必须定义FirstType,{{1}在key()中包装MethodA(),然后将其(作为MethodB()接口)嵌入到仅用于定义这些默认方法的其他结构中{} {1}}和FirstType,然后履行WithKey界面。