Go设计模式-模板方法|8月更文挑战

1,152 阅读1分钟

定义

模板方法是在一个方法中定义一个算法骨架,并将这些步骤推迟到子类中实现,模板方法可以让子类在不改变算法整体的结构向下,重新定义某些步骤。

这里的算法可以认为是业务逻辑。

应用场景

扩展:框架通过模板提供功能扩展点,让框架用户可以在不修改源码的情况下,基于扩展点定制化框架的功能。 复用:复用指的是,子类可以服用父类日共模板方法的代码。

与回调的区别

同步回调

  • 回调基于组合关系来实现,把一个对象传递给另外一个对象,是一种对象之间的关系
  • 模板模式是基于继承关系来实现,子类重写弗雷的抽象方法,是一种类之间的关系。

异步回调

  • 更类似观察者模式

代码

package template
import "fmt"

type Downloader interface {
	Download(uri string)
}

type template struct {
	implement
	uri string
}

type implement interface {
	download()
	save()
}

func newTemplate(impl implement) *template {
	return &template{
		implement: impl,
	}
}

func (t *template) Download(uri string) {
	t.uri = uri
	fmt.Print("prepare downloading\n")
	t.implement.download()
	t.implement.save()
	fmt.Print("finish downloading\n")
}

func (t *template) save() {
	fmt.Print("default save\n")
}

type HTTPDownloader struct {
	*template
}

func NewHTTPDownloader() Downloader {
	downloader := &HTTPDownloader{}
	template := newTemplate(downloader)
	downloader.template = template
	return downloader
}

func (d *HTTPDownloader) download() {
	fmt.Printf("download %s via http\n", d.uri)
}

func (*HTTPDownloader) save() {
	fmt.Printf("http save\n")
}

type FTPDownloader struct {
	*template
}

func NewFTPDownloader() Downloader {
	downloader := &FTPDownloader{}
	template := newTemplate(downloader)
	downloader.template = template
	return downloader
}

func (d *FTPDownloader) download() {
	fmt.Printf("download %s via ftp\n", d.uri)
}

测试代码

package template

import "testing"

func TestExampleHTTPDownloader(t *testing.T) {
	var downloader Downloader = NewHTTPDownloader()

	downloader.Download("http://example.com/abc.zip")
	// Output:
	// prepare downloading
	// download http://example.com/abc.zip via http
	// http save
	// finish downloading
}

func TestExampleFTPDownloader(t *testing.T) {
	var downloader Downloader = NewFTPDownloader()

	downloader.Download("ftp://example.com/abc.zip")
	// Output:
	// prepare downloading
	// download ftp://example.com/abc.zip via ftp
	// default save
	// finish downloading
}

运行结果

=== RUN   TestExampleHTTPDownloader
prepare downloading
download http://example.com/abc.zip via http
http save
finish downloading
--- PASS: TestExampleHTTPDownloader (0.00s)
=== RUN   TestExampleFTPDownloader
prepare downloading
download ftp://example.com/abc.zip via ftp
default save
finish downloading
--- PASS: TestExampleFTPDownloader (0.00s)
PASS

参考资料