定义
模板方法是在一个方法中定义一个算法骨架,并将这些步骤推迟到子类中实现,模板方法可以让子类在不改变算法整体的结构向下,重新定义某些步骤。
这里的算法可以认为是业务逻辑。
应用场景
扩展:框架通过模板提供功能扩展点,让框架用户可以在不修改源码的情况下,基于扩展点定制化框架的功能。 复用:复用指的是,子类可以服用父类日共模板方法的代码。
与回调的区别
同步回调
- 回调基于组合关系来实现,把一个对象传递给另外一个对象,是一种对象之间的关系
- 模板模式是基于继承关系来实现,子类重写弗雷的抽象方法,是一种类之间的关系。
异步回调
- 更类似观察者模式
代码
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