部分实现接口的最佳实践

时间:2016-03-02 12:11:54

标签: go

部分提供默认实施的方式是什么?

为了说明,以下简单的切换开关驱动程序示例是我通过遵循我的OO直觉结束的死胡同......当然它不编译(我知道为什么)而且我不一定愿意做所以。 任何其他解决方案更适合go go哲学实际上更好地正确理解这种共同需求的路径。

完整示例也可以在https://play.golang.org/p/MYED1PB-dS

找到

给出以下界面:

type ToggleSwitch interface {
    TurnOn()
    TurnOff()
    IsOn() bool
    Toggle()
}

Toggle()是一个很好的候选者,可以提供默认实现(即根据当前状态,打开或关闭开关):

// The Toggle() method can already be defined using TurnOn, TurnOff() and IsOn().
type DefaultDriver struct {
}

// The following implementation would be fine for non-optimized cases:
func (d *DefaultDriver) Toggle() {
    state := d.IsOn()
    fmt.Println("generic toogle ->", state)
    if state {
        d.TurnOff()
    } else {
        d.TurnOn()
    }
}

然后一个真正的驱动程序可以使用或不使用它:

// Example of an actual ToggleDriver which should fully implement the interface
// based on the default implementation or not.
// For example, if the toggle switch device has a bult-in toggle command, the
// Toggle() method could be optimized to directly use it.
type DummyDriver struct {
    *DefaultDriver // promote DefaultDriver methods
    state bool
}

func (d *DummyDriver) IsOn() bool {
    return d.state
}

func (d *DummyDriver) TurnOff() {
    d.state = false
}

func (d *DummyDriver) TurnOn() {
    d.state = false
}

// Uncomment me to optimize me...
//func (d *DummyDriver) Toggle() {
//  fmt.Println("specialized toogle ->", d.state)
//  d.state = !d.state
//}

2 个答案:

答案 0 :(得分:3)

在我看来,你要做的事情并不像Go一样。

ToggleSwitch定义了四种明确适用某种状态的方法。为了提供这些方法的任何的实现,您还需要实现该状态(即使该状态不存在,例如通过将这些方法定义为no-ops),但在那时,没有提供所有那些方法是没有意义的。

使用类似Go的类型组合,嵌入式类型通常应该是整个",完整且有用。嵌入式提供的方法仅适用于该领域,没有办法到达父母"或其方法。

如果ToggleSwitch还有其他方法没有处理该状态,那么只提供接口的部分实现是有意义的,但在这一点上更好,更惯用的解决方案是将ToggleSwitch定义为两个独立接口的组合。

换句话说,我不认为那里有一个" Go way"提供接口的部分实现(不是由几个接口组成),因为它在Go中用来定义尽可能小的接口。

答案 1 :(得分:2)

Personnally,我会为DefaultDriver类型实现Toggle,IsOn,TurnOn和TurnOff方法,因此它将满足ToggleSwitch接口。

然后,DummyDriver类型将嵌入DefaultDriver类型。

这样,您可以根据需要为DummyDriver类型实现专门的方法。

结果将是这样的:

package main

import "fmt"

type ToggleSwitch interface {
    TurnOn()
    TurnOff()
    IsOn() bool
    Toggle()
}

type DefaultDriver struct {
    state bool
}

func (d *DefaultDriver) Toggle() {
    state := d.IsOn()
    fmt.Println("generic toogle ->", state)
    if state {
        d.TurnOff()
    } else {
        d.TurnOn()
    }
}

func (d *DefaultDriver) IsOn() bool {
    return d.state
}

func (d *DefaultDriver) TurnOff() {
    d.state = false
}

func (d *DefaultDriver) TurnOn() {
    d.state = true
}

type DummyDriver struct {
    DefaultDriver
    state bool
}

// Uncomment me to optimize me...
//func (d *DummyDriver) Toggle() {
//  fmt.Println("specialized toogle ->", d.state)
//  d.state = !d.state
//}

func main() {
    d := DummyDriver{state: false}
    d.Toggle()
    d.Toggle()
    d.Toggle()
}

https://play.golang.org/p/Xm-8A0xoRb