V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
matrix67
V2EX  ›  Go 编程语言

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

  •  
  •   matrix67 · 2020-09-30 14:41:33 +08:00 · 3576 次点击
    这是一个创建于 1523 天前的主题,其中的信息可能已经有所发展或是发生改变。

    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 就一个方法,之前的那种写法也可行。感觉就是解耦跟好了?

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

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

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