如何在 Go 中实现抽象类?

如何在 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)

}

这不会编译,因为不可能将接口用作接收器。


事实上,我已经回答了我的问题(见下面的答案)。但是,这是实现这种逻辑的惯用方法吗?除了语言的简单性之外,还有什么理由不使用默认实现吗?


慕妹3242003
浏览 284回答 3
3回答

烙印99

其他答案为您的问题提供了替代方案,但是他们提出了不使用抽象类/结构的解决方案,我想如果您有兴趣使用类似抽象类的解决方案,这里是您问题的非常精确的解决方案:package mainimport (&nbsp; &nbsp; "fmt"&nbsp; &nbsp; "time")type Daemon interface {&nbsp; &nbsp; start(time.Duration)&nbsp; &nbsp; doWork()}type AbstractDaemon struct {&nbsp; &nbsp; Daemon}func (a *AbstractDaemon) start(duration time.Duration) {&nbsp; &nbsp; ticker := time.NewTicker(duration)&nbsp; &nbsp; // this will call daemon.doWork() periodically&nbsp;&nbsp;&nbsp; &nbsp; go func() {&nbsp; &nbsp; &nbsp; &nbsp; for {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <- ticker.C&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; a.doWork()&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }()}type ConcreteDaemonA struct {&nbsp;*AbstractDaemonfoo int}func newConcreteDaemonA() *ConcreteDaemonA {&nbsp; a:=&AbstractDaemon{}&nbsp; r:=&ConcreteDaemonA{a, 0}&nbsp; a.Daemon = r&nbsp; return r}type ConcreteDaemonB struct {&nbsp;*AbstractDaemonbar int}func newConcreteDaemonB() *ConcreteDaemonB {&nbsp; a:=&AbstractDaemon{}&nbsp; r:=&ConcreteDaemonB{a, 0}&nbsp; a.Daemon = r&nbsp; return r}func (a *ConcreteDaemonA) doWork() {&nbsp; &nbsp; a.foo++&nbsp; &nbsp; fmt.Println("A: ", a.foo)}func (b *ConcreteDaemonB) doWork() {&nbsp; &nbsp; b.bar--&nbsp; &nbsp; fmt.Println("B: ", b.bar)}func main() {&nbsp; &nbsp; var dA&nbsp; Daemon = newConcreteDaemonA()&nbsp; &nbsp; var dB&nbsp; Daemon = newConcreteDaemonB()&nbsp; &nbsp; dA.start(1 * time.Second)&nbsp; &nbsp; dB.start(5 * time.Second)&nbsp; &nbsp; time.Sleep(100 * time.Second)}如果这仍然不明显如何在 go-lang 中使用抽象类/多继承,这里是具有全面详细信息的帖子。

神不在的星期二

如果您想提供“默认”实现(for Daemon.start()),那不是接口的特性(至少在 Go 中不是)。这是具体(非接口)类型的特征。所以Daemon在你的情况下应该是一个具体的类型,struct因为你希望它有字段,所以很方便。并且要完成的任务可以是一个接口类型的值,或者在简单的情况下只是一个函数值(简单的情况意味着它只有一个方法)。带接口类型在Go Playground上试用完整的应用程序。type Task interface {&nbsp; &nbsp; doWork()}type Daemon struct {&nbsp; &nbsp; task Task}func (d *Daemon) start(t time.Duration) {&nbsp; &nbsp; ticker := time.NewTicker(t)&nbsp; &nbsp; // this will call task.doWork() periodically&nbsp; &nbsp; go func() {&nbsp; &nbsp; &nbsp; &nbsp; for {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <-ticker.C&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; d.task.doWork()&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }()}type MyTask struct{}func (m MyTask) doWork() {&nbsp; &nbsp; fmt.Println("Doing my work")}func main() {&nbsp; &nbsp; d := Daemon{task: MyTask{}}&nbsp; &nbsp; d.start(time.Millisecond*300)&nbsp; &nbsp; time.Sleep(time.Second * 2)}带函数值在这个简单的例子中,这个较短。在Go Playground上试一试。type Daemon struct {&nbsp; &nbsp; task func()}func (d *Daemon) start(t time.Duration) {&nbsp; &nbsp; ticker := time.NewTicker(t)&nbsp; &nbsp; // this will call task() periodically&nbsp; &nbsp; go func() {&nbsp; &nbsp; &nbsp; &nbsp; for {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <-ticker.C&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; d.task()&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }()}func main() {&nbsp; &nbsp; d := Daemon{task: func() {&nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("Doing my work")&nbsp; &nbsp; }}&nbsp; &nbsp; d.start(time.Millisecond * 300)&nbsp; &nbsp; time.Sleep(time.Second * 2)}

九州编程

一个简单的解决方案是移动daemon *Daemon到参数列表(从而start(...)从界面中删除):type Daemon interface {&nbsp; &nbsp; // start(time.Duration)&nbsp; &nbsp; doWork()}func start(daemon Daemon, duration time.Duration) { ... }func main() {&nbsp; &nbsp; ...&nbsp; &nbsp; start(dA, 1 * time.Second)&nbsp; &nbsp; start(dB, 5 * time.Second)&nbsp; &nbsp; ...}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go