finish template_method pattern

This commit is contained in:
Edward 2020-05-03 21:08:56 +08:00
parent 87d44adc6d
commit 0932602a56
3 changed files with 89 additions and 67 deletions

View File

@ -1,9 +1,17 @@
# 模版方法模式
模板方法就是为了将方法和结构各自实现分开到不同的地方,并且可以单独实现,往往是将将方法/处理器的实现延迟到子类或者其他可注入的类型中。
模板方法主要是为了解决一些方法通用性问题,将通用方法放在父类,需要单独实现的方法放在其他类中,将通用方法和变化的方法分开,各自实现分开到不同的地方,并且可以单独实现,往往是将将变化部分方法/处理器的实现延迟到子类或者其他可注入的类型中。
模板方法就是设计的核心思想体现,如果把其他的模式都忘了,只要还记得一个模式,就能变化其他的任意模块,设计模式的作用要点就是要封装变化点,尽量降低耦合,方法,结构分离,接口继承,结构继承,都是为了将不同的变化点封装到不同的模块,以使其能够单独演化,尽量做到通用。
go 的结构对象和接口的分离做的更彻底,不需要像其他语言一样显式声明继承或者实现关系,所以在实现模板方法时候更灵活。
此处需要注意:因为父类需要调用子类方法,所以子类需要匿名组合父类的同时,父类需要持有子类的引用。
模板方法的特点在于,定义一好一套接口,定义基本类型结构作为父类,同时在父类中组合好调用方式,并实现好通用的方法,变化部分的接口的具体实现可以在子类或者其他地方实现。
现实生活中工作中,文件打印就是一个很好的模板方法的例子,我们打印操作一般式:
文件--->设置--->打印.
但是对于不同的打印方式对于同一个文件的打印实现可能略有不同。
比如虚拟打印到 pdf或者xps与打印打纸质文件需要的设置和打印肯定式不同的虚拟打印你肯定需要指明输出路径纸质打印需要可能需要设置打印质量质量越高越费墨。

View File

@ -2,68 +2,78 @@ package templatemethod
import "fmt"
type Downloader interface {
Download(uri string)
////////////////////////////////
//使用打印的例子
//IPrinter 定义打印的流程
type IPrinter interface {
Set(mark string)
Print()
}
type template struct {
implement
uri string
//Printer 定义基本结构类型
type Printer struct {
workerMark string
printer IPrinter //指项实际工作的类型
}
type implement interface {
download()
save()
//LoadDrive 载入驱动
func (p *Printer) LoadDrive() {
fmt.Print("init print drive\n")
}
func newTemplate(impl implement) *template {
return &template{
implement: impl,
//UnLoadDrive 卸载驱动
func (p *Printer) UnLoadDrive() {
fmt.Print("unload drive\n")
}
//Set 设置参数,这是变化的部分
func (p *Printer) Set(mark string) {
p.workerMark = mark
//调用实现
if p.printer != nil {
p.printer.Set(mark)
}
}
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")
//Print 执行打印,这是变化的部分
func (p *Printer) Print() {
//调用实现
fmt.Print("print with task mark: ", p.workerMark, "\n")
if p.printer != nil {
p.printer.Print()
}
}
func (t *template) save() {
fmt.Print("default save\n")
//DoPrintWork 打印
//DoPrintWork 定义了打印的流程
func (p *Printer) DoPrintWork() {
p.LoadDrive()
p.Set(p.workerMark)
p.Print()
p.UnLoadDrive()
}
type HTTPDownloader struct {
*template
//PDF 虚拟打印
type PDF struct {
Printer
output string
}
func NewHTTPDownloader() Downloader {
downloader := &HTTPDownloader{}
template := newTemplate(downloader)
downloader.template = template
return downloader
//Print to a PDF
func (p *PDF) Print() {
fmt.Print("print to PDF ,save to ", p.output, "\n")
}
func (d *HTTPDownloader) download() {
fmt.Printf("download %s via http\n", d.uri)
//DevicePrinter 设备打印机
type DevicePrinter struct {
Printer
quality int //1,2,3表示打印高中低
}
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)
//Print to a Paper
func (d *DevicePrinter) Print() {
fmt.Print("print to Paper ,with quality: ", d.quality, "\n")
}

View File

@ -1,23 +1,27 @@
package templatemethod
func ExampleHTTPDownloader() {
var downloader Downloader = NewHTTPDownloader()
import "testing"
func TestTemplateMethod(t *testing.T) {
//打印机
aprinter := Printer{}
//这个是被复合的work流程
aprinter.DoPrintWork()
//连接PDF打印机
aprinter.printer = &PDF{output: "./home"}
aprinter.Set("---PDF--")
//打印
aprinter.DoPrintWork()
//连接纸质打印机
aprinter.printer = &DevicePrinter{quality: 5}
aprinter.Set("---Paper--")
//打印
aprinter.DoPrintWork()
downloader.Download("http://example.com/abc.zip")
// Output:
// prepare downloading
// download http://example.com/abc.zip via http
// http save
// finish downloading
}
func ExampleFTPDownloader() {
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
}