如何在Go语言中实现一个抽象类?由于Go语言不允许在接口中包含字段,因此这将是一个无状态对象。那么,换句话说,在Go语言中是否有可能为一个方法提供某种默认的实现呢?
请考虑以下示例:
type Daemon interface {
start(time.Duration)
doWork()
}
func (daemon *Daemon) start(duration time.Duration) {
ticker := time.NewTicker(duration)
// this will call daemon.doWork() periodically
go func() {
for {
<- ticker.C
daemon.doWork()
}
}()
}
type ConcreteDaemonA struct { foo int }
type ConcreteDaemonB struct { bar int }
func (daemon *ConcreteDaemonA) doWork() {
daemon.foo++
fmt.Println("A: ", daemon.foo)
}
func (daemon *ConcreteDaemonB) doWork() {
daemon.bar--
fmt.Println("B: ", daemon.bar)
}
func main() {
dA := new(ConcreteDaemonA)
dB := new(ConcreteDaemonB)
start(dA, 1 * time.Second)
start(dB, 5 * time.Second)
time.Sleep(100 * time.Second)
}
这将不会编译,因为它不可能使用接口作为接收器。
事实上,我已经回答了我的问题(见下面的答案)。然而,这是实现这种逻辑的惯用方法吗?除了语言的简单性之外,还有什么理由不使用默认实现吗?
6条答案
按热度按时间ki1q1bka1#
其他的答案提供了一个替代你的问题,但是他们提出的解决方案没有使用抽象类/结构,我猜如果你有兴趣使用抽象类一样的解决方案,这里是非常精确的解决方案,你的问题:
Go plaground
如果这还不清楚如何在go-lang中使用抽象类/多重继承,这里有一个完整的细节。Abstract Classes In Go
lpwwtiir2#
如果你想提供一个“default”实现(对于
Daemon.start()
),这不是 interface 的特性(至少在Go语言中不是),而是 concrete(非接口)类型的特性。所以
Daemon
在你的例子中应该是一个具体的类型,方便的是struct
,因为你希望它有字段。要完成的任务可以是一个接口类型的值,或者在一个简单的例子中只是一个函数值(简单的例子意味着它只有一个方法)。带接口类型
在Go Playground上试用完整的应用程序。
带函数值
在这个简单的例子中,这个更短。在Go Playground上试试。
jjhzyzn03#
一个简单的解决方案是将
daemon *Daemon
移到参数列表中(从而从接口中删除start(...)
):x7yiwoj44#
你可以在go中实现抽象类。
定义:
现在
object
是一个抽象类,就像java的。您可以继承它并使用其成员:
并使用
object
与concreteObject
的方法:并将抽象对象投射到具体对象上:
就像其他OOP语言一样。
oogrdqng5#
Max Malysh提供的解决方案在某些情况下可以工作,如果你不需要工厂的话。但是Adrian Witas提供的解决方案可能会导致循环依赖问题。
这就是我实现抽象类的方法,这是一种尊重循环依赖关系和良好工厂模式的简单方法。
让我们假设我们的组件具有以下包结构
定义组件的定义,在本例中它将在此处定义:
组件/类型.go
现在,假设我们要创建一个抽象类,它只实现Sum和Average,但在此抽象实现中,我们希望能够使用已实现的A和B返回的值
要实现这一点,我们应该为抽象实现的抽象成员定义另一个接口
组件/基础/类型.go
然后我们就可以着手实现抽象的“类”
组件/基础/抽象.go
现在,我们开始实施
组件/impl 1/impl.go//对impl 2取类似值
我们使用一个单独的接口而不是使用Adrian Witas示例的原因是,如果我们在本例中使用相同的接口,如果我们导入impl*中的base包以使用抽象“类”,并且导入components包中的impl包,以便工厂可以注册它们,我们将发现循环引用。
所以我们可以有一个这样的工厂实现
组件/工厂.go
4zcjmb1e6#
抽象类的功能有以下要求1.不应创建抽象类的直接示例2.应提供默认字段和方法。
接口和结构体的组合可以用来满足以上两个要求。
这里要提到的一个重要点是所有默认方法都应该有iAlpha作为第一个参数,如果默认方法需要调用任何未实现的方法,它们将在此接口上调用。这与我们在上面的公共方法- www.example.com()中所做的相同i.work。
来源:https://golangbyexample.com/go-abstract-class/