模板模式可以把一个流程抽象起来,一个流程中首先调用哪一个函数,后面再调用哪一个函数,基本的流程基本是固定的。只是每一步要怎么做跟具体类型有关系,这时候就很适合用模板模式了。

定义:一个抽象类公开定义了执行它的方法的方式/模板。 它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行。 这种类型的设计模式属于行为型模式

但是在GOLANG的实现中,需要用到这些知识:当一个子类通过直接在子类中添加父类类型名的方法组合,如果子类没有覆盖父类的方法,那么可以直接通过子类调用父类;如果子类覆盖了父类的方法,那么就会使用子类新定义的方法。

模板实现代码:

package templatemethodimport "fmt"type Downloader interface {Download(uri string)}type template struct {implementuri string}type implement interface {download()save()}func newTemplate(impl implement) *template {return &template{implement:impl,}}func (t *template)Download(uri string) {t.uri = urifmt.Print("prepare downloading\n")自由的裙子.download()自由的裙子.save()fmt.Print("finish downloading\n")}func (t *template)save() {fmt.Print("default save\n")}/*这里 HTTPDownloader struct包含(封装)了*template, 因为*template实现了Download(uri string)方法,在我们HTTPDownloader.Download(sting)的时候,其实调用的是*template实现的那一个,这里也是允许认为HTTPDownloader实现了Download(uri string)方法的,所以可以将HTTPDownloader实例赋值给Downloader实例。就像下面的NewHTTPDownloader()函数直接将HTTPDownloader实例赋值给Downloader实例那样子。如果我们在HTTPDownloader结构体中添加其他的东西导致HTTPDownloader.Download(sting)这个调用失败,NewHTTPDownloader()这个函数就编译不通过了。*/type HTTPDownloader struct {*template}func NewHTTPDownloader() Downloader {downloader := &HTTPDownloader{}template := newTemplate(downloader)downloader.template = templatereturn downloader}func (d *HTTPDownloader)download() {fmt.Printf("download %s via http\n", d.uri)}/*这里如果我把下面的save函数注释掉,*HTTPDownloader.save()则会调用 *template 实现的save()方法。上层的把底层的覆盖了,这个有点用处。*/func (*HTTPDownloader)save() {fmt.Printf("http save\n")}type FTPDownloader struct {*template}func NewFTPDownloader() Downloader {downloader := &FTPDownloader{}template := newTemplate(downloader)downloader.template = templatereturn downloader}func (d *FTPDownloader)download() {fmt.Printf("download %s via ftp\n", d.uri)}

测试函数:

package templatemethodimport "testing"func TestHTTPDownloader(t *testing.T) {var downloader Downloader = NewHTTPDownloader()downloader.Download("http://example.com/abc.zip")}func TestFTPDownloader(t *testing.T) {var downloader Downloader = NewFTPDownloader()downloader.Download("ftp://example.com/abc.zip")}

 结果:
=== RUN   TestHTTPDownloader
prepare downloading
download http://example.com/abc.zip via http
http save //这里使用了http类型实现的save方法。
finish downloading
--- PASS: TestHTTPDownloader (0.00s)
=== RUN   TestFTPDownloader
prepare downloading
download ftp://example.com/abc.zip via ftp
default save  //ftp类没有save方法,直接调用默认的*template.save方法
finish downloading
--- PASS: TestFTPDownloader (0.00s)
PASS

Process finished with exit code 0