模板方法模式

7.1 模式动机

模版方法模式使用继承机制,把通用步骤和通用方法放到父类中,把具体实现延迟到子类中实现。使得实现符合开闭原则。

如实例代码中通用步骤在父类中实现(准备下载保存收尾)下载和保存的具体实现留到子类中,并且提供 保存方法的默认实现。

因为Golang不提供继承机制,需要使用匿名组合模拟实现继承。

此处需要注意:因为父类需要调用子类方法,所以子类需要匿名组合父类的同时,父类需要持有子类的引用。

7.2 Go语言实现

templatemethod.go

  1. package templatemethod
  2. import "fmt"
  3. type Downloader interface {
  4. Download(uri string)
  5. }
  6. type template struct {
  7. implement
  8. uri string
  9. }
  10. type implement interface {
  11. download()
  12. save()
  13. }
  14. func newTemplate(impl implement) *template {
  15. return &template{
  16. implement: impl,
  17. }
  18. }
  19. func (t *template) Download(uri string) {
  20. t.uri = uri
  21. fmt.Print("prepare downloading\n")
  22. t.implement.download()
  23. t.implement.save()
  24. fmt.Print("finish downloading\n")
  25. }
  26. func (t *template) save() {
  27. fmt.Print("default save\n")
  28. }
  29. type HTTPDownloader struct {
  30. *template
  31. }
  32. func NewHTTPDownloader() Downloader {
  33. downloader := &HTTPDownloader{}
  34. template := newTemplate(downloader)
  35. downloader.template = template
  36. return downloader
  37. }
  38. func (d *HTTPDownloader) download() {
  39. fmt.Printf("download %s via http\n", d.uri)
  40. }
  41. func (*HTTPDownloader) save() {
  42. fmt.Printf("http save\n")
  43. }
  44. type FTPDownloader struct {
  45. *template
  46. }
  47. func NewFTPDownloader() Downloader {
  48. downloader := &FTPDownloader{}
  49. template := newTemplate(downloader)
  50. downloader.template = template
  51. return downloader
  52. }
  53. func (d *FTPDownloader) download() {
  54. fmt.Printf("download %s via ftp\n", d.uri)
  55. }

templatemethod_test.go

  1. package templatemethod
  2. func ExampleHTTPDownloader() {
  3. var downloader Downloader = NewHTTPDownloader()
  4. downloader.Download("http://example.com/abc.zip")
  5. // Output:
  6. // prepare downloading
  7. // download http://example.com/abc.zip via http
  8. // http save
  9. // finish downloading
  10. }
  11. func ExampleFTPDownloader() {
  12. var downloader Downloader = NewFTPDownloader()
  13. downloader.Download("ftp://example.com/abc.zip")
  14. // Output:
  15. // prepare downloading
  16. // download ftp://example.com/abc.zip via ftp
  17. // default save
  18. // finish downloading
  19. }