知名视频下载工具 annie 的一个大重构挺有意思。

2020-09-30 14:41:33 +08:00
 matrix67

annie 是一个视频下载工具。能够下各个视频网站的视频到本地。

然后之前它下载,都是在 main 函数里面根据 url 进行判断,然后每个包自己实现 Extract 方法。具体为有一个 download 函数

func download(videoURL string) error {
	var (
		domain string
		err    error
		data   []downloader.Data
	)
……
	switch domain {
	case "douyin", "iesdouyin":
		data, err = douyin.Extract(videoURL)
	case "bilibili":
		data, err = bilibili.Extract(videoURL)
	case "bcy":
		data, err = bcy.Extract(videoURL)
	case "pixivision":
		data, err = pixivision.Extract(videoURL)
	case "youku":
		data, err = youku.Extract(videoURL)
很多这边就不贴了
 ……

}

最近有个更新,commit 为 424f8def refactor the whole structure (#676), 作者重构了一下,引入了 interface 。具体实现为:

var extractorMap map[string]types.Extractor

func init() {
	douyinExtractor := douyin.New()
	youtubeExtractor := youtube.New()

	extractorMap = map[string]types.Extractor{
		"": universal.New(), // universal extractor

		"douyin":     douyinExtractor,
		"iesdouyin":  douyinExtractor,
		"bilibili":   bilibili.New(),
		"bcy":        bcy.New(),
		"pixivision": pixivision.New(),
		"youku":      youku.New(),
		"youtube":    youtubeExtractor,
		"youtu":      youtubeExtractor, // youtu.be
	……
	}
}

然后 extract 里面

extractor := extractorMap[domain]
videos, err := extractor.Extract(u, option)

每个包实现了Extractor接口 Extract 方法。

// Extractor implements video data extraction related operations.
type Extractor interface {
	// Extract is the main function to extract the data.
	Extract(url string, option Options) ([]*Data, error)
}

这个重构还是挺有意思,作者应该早就想改了,但是是一个大工程,不知道作者心路历程是咋样滴 。

我想问问 extractorMap[domain] 这个用法是比较 native 的吗。另外好像仅仅针对这个问题,用接口的方法没太省事儿,因为 Extractor 就一个方法,之前的那种写法也可行。感觉就是解耦跟好了?

下面是之前学习看视频的时候说用接口的好处。

3474 次点击
所在节点    Go 编程语言
16 条回复
xgfan
2020-09-30 14:53:49 +08:00
同样新增一个视频网站下载器
第一种,理论上需要修改 download 方法。
第二种,只需要在这个下载器初始化的时候,注册到 extractorMap 中就完事了。
第二种 1 是把下载和其他逻辑分离开来了。2 是利于拓展。

总之就是很常见的模式,具体叫啥名忘记了……
lijialong1313
2020-09-30 15:16:57 +08:00
@xgfan 工厂模式吧……
lazyfighter
2020-09-30 15:26:57 +08:00
我记得之前看文章写的就是这种,当你的分支足够多的时候就可以抽象出 Map<String,Executor>来搞,最近那个 cola 框架底层我记得就是这种设计,根据不同的场景调用不同的 Executor
zxlzy
2020-09-30 15:31:33 +08:00
这个是非常常见的设计了。。
Geekerstar
2020-09-30 16:47:44 +08:00
看了一下,他支持的网站挺多的,有没有人试过下载的下来么? https://imgchr.com/i/0u3qde
smilekung
2020-09-30 16:56:21 +08:00
这不就是策略模式
matrix67
2020-09-30 16:56:48 +08:00
@Geekerstar #5 华生。。。
@zxlzy #4 嗯嗯是的。go 里面我还第一次见。学习一下。
@lazyfighter #3 这个我再 py 里面看到过很多。
guonaihong
2020-09-30 19:25:36 +08:00
需要动态选择插件的时候一般都是这么做的。以前在 c 里面做音频编解码,就是用字符串选择编解码器,达到动态桥接的效果。
WilliamYang
2020-09-30 20:31:16 +08:00
就是策略模式,我天天用
qiumaoyuan
2020-09-30 20:35:07 +08:00
没有消除重复的模式没有意义。
matrix67
2020-09-30 21:40:39 +08:00
@WilliamYang 查了下感觉更偏向工厂模式。
mxalbert1996
2020-09-30 22:12:25 +08:00
@lijialong1313 @matrix67
这明显不是工厂模式,都不实例化叫什么工厂模式。
reus
2020-10-01 13:29:02 +08:00
就一个 map,也能叫模式?
太常见的用法了
lijialong1313
2020-10-01 14:06:15 +08:00
@mxalbert1996 个人觉得的话,如果我要做类似这样一个东西,我会做的像工厂模式。每一个策略,在下载时会实例化一个对象,这样对不同的下载任务就可以不同的管理。
lxilu
2020-10-01 22:39:50 +08:00
很自然的做法,谈不上设计模式
@mxalbert1996 .New() 好像是实例化?
mxalbert1996
2020-10-01 23:12:43 +08:00
@lxilu 工厂模式指的是工厂根据客户需求生产类的实例后交付客户,你见过哪个工厂从头到尾只生产一个实例还一直留着每来一个客户就借他用一下的?

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/711889

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX