简介
模式定义
模板方法(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 类型,只能使用而不能修改。
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/>";
}