设计模式 - 模板方法设计模式

模板方法及各种语言的实现

简介

模式定义

模板方法(Template Method)设计模式中,定义了一个操作中算法的骨架,而将一些步骤延迟到子类中。子类可以复用算法的结构,同时可用重写算法的某些特定步骤。

模式特点

模板方法将稳定的东西(流程,不需要重写的方法)放在类库中,只将变化的东西开放给应用开发人员。

这里写图片描述

示例

例如,程序框架定义了稳定的算法流程 run(),且在其依赖的三个方法中,有虚方法 f2()

class Lib
{
public:
	void run()
	{
		f1();
		f2();
		f3();
	}
	
	void f1()
	{
		//...
	}
	
	virtual void f2()
	{
		//...
	}
	
	void f3()
	{
		//...
	}
}

应用开发人员实现自己的 f2(),然后启动流程:

class App
{
public:
	virtual void f2()
	{
		//...
	}

	run();
}

早绑定和晚绑定

将函数体和函数调用关联起来,就叫绑定(Connecting a function call to a function body is called binding)。

  • 早绑定(Early binding)
    When binding is performed before the program is run (by the compiler and linker), it’ s called early binding
    在程序运行之前(也就是编译和链接时)就发生的绑定是早绑定。
  • 晚绑定(late binding)
    late binding, which means the binding occurs at runtime, based on the type of the object. When a language implements late binding, there must be some mechanism to determine the type of the object at runtime and call the appropriate member function.
    晚绑定发生在运行时,基于不同类型的对象。如果一种语言实现了晚绑定,就必须有某种机制判断对象的具体类型然后调用合适的成员函数。

晚绑定可以实现多态。父类中定义 virtual 虚方法(相当于抽象方法),在子类中重载时,只有在运行时才会知道用哪个子类。

简单的 C++ 虚方法示例,其中虚方法 sleep 发生晚绑定:

#include <iostream>
using namespace std;

class Animal
{
public:
	virtual void sleep()
	{
		cout << "Animal sleep!" << endl;
	}
 
	void breath()
	{
		cout << "Animal breath!" << endl;
	}
};
 
class Fish :public Animal
{
public:
	virtual void sleep()
	{
		cout << "Fish sleep!" << endl;
	}
	void breath()
	{
		cout << "Fish breath!" << endl;
	}
};
int main()
{
	Fish f;
	Animal* a = &f; //基类指针指向派生类
	a->breath();
	a->sleep();
	return 0;
}

输出:

Animal breath!
Fish sleep!

PHP 代码示例

模板方法必须是 final 类型,只能使用而不能修改。

<?php

abstract class Lib {
    private function step1() {
        echo "step 1 run".PHP_EOL;
    }
    
    public final function run() {
        $this->step1();
        $this->step2();
    }
    abstract protected function step2();
}

class App extends Lib {
    protected function step2() {
        echo "step 2 in App run".PHP_EOL;
    }
}

$app = new App();
$app->run();
abstract class TemplateAbstract {
    //模板方法,设置算法的流程
    public final function showBookTitleInfo($book_in) {
        $title = $book_in->getTitle();
        $author = $book_in->getAuthor();
        $processedTitle = $this->processTitle($title);
        $processedAuthor = $this->processAuthor($author);
        if (NULL == $processedAuthor) {
            $processed_info = $processedTitle;
        } else {
            $processed_info = $processedTitle.' by '.$processedAuthor;
        }
        return $processed_info;
    }
    // 抽象方法,必须重写
    abstract function processTitle($title);
    // 这个可以不重写,这样会返回 NULL
    function processAuthor($author) {
        return NULL;
    } 
}

class TemplateExclaim extends TemplateAbstract {
    function processTitle($title) {
      return Str_replace(' ','!!!',$title); 
    }
    function processAuthor($author) {
      return Str_replace(' ','!!!',$author);
    }
}

class TemplateStars extends TemplateAbstract {
    function processTitle($title) {
        return Str_replace(' ','*',$title); 
    }
}

class Book {
    private $author;
    private $title;
    function __construct($title_in, $author_in) {
        $this->author = $author_in;
        $this->title  = $title_in;
    }
    function getAuthor() {return $this->author;}
    function getTitle() {return $this->title;}
    function getAuthorAndTitle() {
        return $this->getTitle() . ' by ' . $this->getAuthor();
    }
}

  writeln('BEGIN TESTING TEMPLATE PATTERN');
  writeln('');
 
  $book = new Book('PHP for Cats','Larry Truett');
 
  $exclaimTemplate = new TemplateExclaim();  
  $starsTemplate = new TemplateStars();
 
  writeln('test 1 - show exclaim template');
  writeln($exclaimTemplate->showBookTitleInfo($book));
  writeln('');

  writeln('test 2 - show stars template');
  writeln($starsTemplate->showBookTitleInfo($book));
  writeln('');

  writeln('END TESTING TEMPLATE PATTERN');

  function writeln($line_in) {
    echo $line_in."<br/>";
  }

Java 模板方法代码示例

public class Main
{
	public static void main (String[] args)
	{
	    App app = new App();
	    app.run();
	}
}

class App extends Lib {
    public void step2() {
        System.out.println("run step2 in app");
    }
}

abstract class Lib {
    public final void run() {
        step1();
        step2();
        step3();
    }
    public void step1() {
        System.out.println("run step1 in lib");
    }
    
    public abstract void step2();
    
    public void step3() {
        System.out.println("run step3 in lib");
    }
}

Golang 模板方法代码示例

package main

import "fmt"

type LibInterface interface {
    step2()
}

type Lib struct {
    LibInterface
}
func (l *Lib) run() {
    l.step1()
    l.step2()
    l.step3()
}
func (l *Lib) step1() {
    fmt.Println("step1 in Lib")
}
func (l *Lib) step3() {
    fmt.Println("step3 in Lib")
}

type App struct {}
func (a *App) step2() {
    fmt.Println("step2 in App")
}

func main() {
    l := Lib{LibInterface: &App{}}
    l.run()
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值