关于interface和struct
来源:16-2 简单调度器

nitros
2020-03-16
老师好
在简单调度器这里,有一些不太清楚的地方希望老师能给解惑一下。
主要是关于结构体和接口这里的设计理念问题。
关于简单调度器
首先我们先做了一个并发版的引擎
type ConcurrentEngine struct {
}
之后我们围绕并发版引擎做了一些方法。比如submit
这时候就有了
type Scheduler interface {
Submit()
}
好了问题来了。
这里老师给的代码是
e.Scheduler.Submit(r)
然后在
ConcurrentEngine 肚子里放了调度器
我想问下
通过代码
e.Submit(r)
然后我再写个关于并发引擎的方法来实现这个interface不可以吗?
func (c *ConcurrentEngine)Submit(request Request) {}
老师那样写的好处是什么呢。那里的设计理念和中心思想是什么呢?
还请老师给解惑一下
另外附上自己更改的一部分理解后的代码。麻烦老师给指点下哪里错误了
package engine
import (
"log"
)
type ConcurrentEngine struct {
WorkerCount int
requestChan chan Request
}
type Scheduler interface {
Submit(Request)
}
func (*ConcurrentEngine) Submit(request Request, in chan Request) {
go func() {
in <- request
}()
}
func (c *ConcurrentEngine) Run(Seeds ...Request) {
out := make(chan ParserResult)
c.requestChan = make(chan Request)
for _, req := range Seeds {
c.Submit(req, c.requestChan)
}
for i := 0; c.WorkerCount > i; i++ {
c.createWorker(c.requestChan, out)
}
for {
result := <-out
for _, re := range result.Request {
c.Submit(re, c.requestChan)
}
for _, item := range result.Items {
log.Printf("got item : %s\n", item)
}
}
}
func (*ConcurrentEngine) createWorker(in chan Request, out chan ParserResult) {
go func() {
for {
req := <-in
result, err := Worker(req)
if err != nil {
continue
}
out <- result
}
}()
}
2回答
-
你这个相当于把simple scheduler的部分整合进了这个ConcurrentEngine。可以看一下simple scheduler本身没几行代码。https://git.imooc.com/coding-180/coding-180/src/master/crawler/scheduler/simple.go
首先的问题是scheduler要不要整合进来,还是像我课上那样作为一个单独的模块。我的建议是做成单独的模块。本身它的任务很明确,就是将request分发给worker,没有任何业务逻辑,但是可以做的很复杂。
有两个模块的前提下,我们才需要使用接口的概念。让两个scheduler(https://git.imooc.com/coding-180/coding-180/src/master/crawler/scheduler/simple.go 和 https://git.imooc.com/coding-180/coding-180/src/master/crawler/scheduler/queued.go )都去实现scheduler接口。那么我们这里在concurrentEngine里面就可以把任务交给scheduler去分发,具体就体现在你这行疑问的代码:
e.Scheduler.Submit(r)
你的修改是把两个模块合成一个模块。当然也能运行,但这样的情况下就不需要存在接口了。Submit函数本身可以留着,但是
type Scheduler interface {
Submit()
}就不需要了。我们没有这个接口,也可以调用Submit函数,并不是说一定要有接口或者一定不需要。可以考虑一下你这里的Scheduler接口并没有被用到,只是被实现了,但是没人用。在c.Submit(req, c.requestChan)是直接调用函数,没有通过接口。
接口的作用是一个模块(比如ConcurrentEngine)要调用另一个模块(比如SimpleScheduler)的时候,使用者(这里指ConcurrentEngine)说,我需要跟我合作的模块满足Scheduler接口。
142020-03-18 -
ccmouse
2020-03-18
我又看了下问题,问题在于,
应该是:因为我要分成两个模块,所以要定义一个scheduler接口,
而不是:因为有一个scheduler接口,所以要分成两个模块。
分两个模块的原因是scheduler的任务很明确,就是将request分发给worker,没有任何业务逻辑,但是可以做的很复杂。本身我们也的确实现了两个scheduler,它们都能通过Scheduler接口和ConcurrentEngine进行工作。
00
相似问题