Golang中如何优雅实现模版方法
模版方法是大厂复杂业务逻辑中使用的最多的一种设计模式了,在一些业务庞大、成熟的代码中真的可以说是随处可见。常见的业务场景比方说执行器、校验器之类;其主要目的是可维护性。新增一个执行器/校验器之需要写差异化逻辑,不会把代码搞成烟囱那种难以看懂的模式。
对于Java来说,模版方法的实现方式非常简单,一般只需要一个抽象类,和一堆实现类就可以实现。
具体操作是,先创建抽象类,定义模板方法规定操作顺序,再设抽象方法作步骤占位,由子类继承并重写抽象方法,调用模板方法时按顺序执行,依子类重写内容展现差异化行为。
但是在golang中没有继承、没有抽象类,网上不少人强行用java的方式些golang,到最后反而让代码变地非常难以理解。
经过摸索之后,我写了一套golang当中实现模版方法模式的代码,主要使用了golang组合为先、面向接口编程的编程思想。其中使用了一个接口,一个模版类和接口的实现类,其中实现不当的地方,欢迎大家讨论
package templatemethod import "fmt" // 实现方需要实现的差异化接口 type DownloadLogic interface { download(uri string) save() } type HTTPDownloader struct{} func (d *HTTPDownloader) download(uri string) {} func (d *HTTPDownloader) save() {} type FTPDownloader struct{} func (d *FTPDownloader) download(uri string) {} func (d *FTPDownloader) save() {} type DownLoadExecutor struct { // 组合一个接口 downloader DownloadLogic } func (d *DownLoadExecutor) doSomeOtherThings(){} // 模版方法,进行逻辑编排 func (d *DownLoadExecutor) doDownloadExecute(uri string) { doSomeOtherThings() d.downloader.download(uri) doSomeOtherThings() d.downloader.save() doSomeOtherThings() } // DownloadExecutorsMap 提供根据executor名称拿到下载器的能力 // 某些时候「比如校验器」更多是维护成一个list var DownloadExecutorsMap = map[string]*DownLoadExecutor{ "http": {downloader: &HTTPDownloader{}}, "ftp": {downloader: &FTPDownloader{}}, } // Use 模拟使用方的业务逻辑 func Use() error { executor, ok := DownloadExecutorsMap["http"] if !ok { return fmt.Errorf("http download executor not found") } executor.doDownloadExecute("https://www.google.com") return nil }