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