Published on

设计模式(22)——模板方法 Template Method

Authors
  • avatar
    Name
    Leon
    Twitter

二十二、Template Method(模板方法,类行为模式)

1. 意图:

  定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。Template Method 使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。

2. 适用:

  1. 一次性实现一个算法的不变部分,并将可变的行为留给子类来实现。
  2. 各子类中公共的行为应被提取出来并集中到一个公共类中以避免代码重复。这是 Opdyke 和 Johnson 所描述过的“重分解以一般化”的一个很好的例子。首先识别现有代码中的不同之处,并且将不同之处分享为新的操作。最后,用一个调用这些新的操作的模板方法来替换这些不同的代码。
  3. 控制子类扩展。模板方法只在特定点调用“hook”操作,这样就只允许在这些点进行扩展。

3. 类图:

4. 相关模式

  Factory Method 模式常被模板方法调用。如 PrimitiveOperation() 就可以是一个 Factory Method,它由模板方法函数 TemplateMethod() 调用。   Strategy: 模板方法使用继承来改变算法的一部分。 Strategy 使用委托(组合)来改变整个算法。

5. Strategy 与 Template Method:

  可以看到 Strategy 模式和 Template 模式解决了类似的问题,但是 Strategy 模式是将逻辑(算法)封装到一个类,并采取组合(委托)的方式解决这个问题,而 Template 是采用继承的方式实现这一点:将逻辑(算法)框架放在抽象基类中,并定义好细节的接口,子类中实现细节。Strategy 和 Tmeplate 模式实际是实现一个抽象接口的两种方式:继承和组合之间的区别。要实现一个抽象接口,继承是一种方式:我们将抽象接口声明在基类中,将具体的实现放在具体子类中。组合(委托)是另外一种方式:我们将接口的实现放在被组合对象中,将抽象接口放在组合类。

6. C++实现:

  1. 编写抽象基类 AbstractClass,含有一个公有的模板方法函数 TemplateMethod(),函数定义中按一定步骤(顺序)调用具体的其它基本操作的函数如 PrimitiveOperation1()PrimitiveOperation2(),基本操作函数声明为 protected 的,保证其子类可以重写,而外部不可访问
  2. 外部只能调用 AbstractClass 的公有函数 TemplateMethod(),不能任意调用 protected 的基本操作函数,所能模板方法函数约束了基本操作的执行步骤,从而实现模板方法模式。

Template.h

//Template.h
#pragma once

class AbstractClass {
public:
	virtual ~AbstractClass();
	void TemplateMethod();
protected:
	virtual void PrimitiveOperation1() = 0;
	virtual void PrimitiveOperation2() = 0;
	AbstractClass();
private:
};

class ConcreteClass1 : public AbstractClass {
public:
	ConcreteClass1();
	~ConcreteClass1();
protected:
	void PrimitiveOperation1();
	void PrimitiveOperation2();
private:
};

class ConcreteClass2 : public AbstractClass {
public:
	ConcreteClass2();
	~ConcreteClass2();
protected:
	void PrimitiveOperation1();
	void PrimitiveOperation2();
private:
};

Template.cpp

//Template.cpp
#include "Template.h"
#include <iostream>
using namespace::std;

AbstractClass::AbstractClass() {}
AbstractClass::~AbstractClass() {}
void AbstractClass::TemplateMethod() {
	this->PrimitiveOperation1();
	this->PrimitiveOperation2();
}
ConcreteClass1::ConcreteClass1() {}
ConcreteClass1::~ConcreteClass1() {}
void ConcreteClass1::PrimitiveOperation1() {
	cout << "ConcreteClass1...PrimitiveOperation1" << endl;
}
void ConcreteClass1::PrimitiveOperation2() {
	cout << "ConcreteClass1...PrimitiveOperation2" << endl;
}
ConcreteClass2::ConcreteClass2() {}
ConcreteClass2::~ConcreteClass2() {}
void ConcreteClass2::PrimitiveOperation1() {
	cout << "ConcreteClass2...PrimitiveOperation1" << endl;
}
void ConcreteClass2::PrimitiveOperation2() {
	cout << "ConcreteClass2...PrimitiveOperation2" << endl;
}

main.cpp

//main.cpp
#include "Template.h"
#include <iostream>
using namespace::std;

int main(int argc, char* argv[]) {
	AbstractClass* p1 = new ConcreteClass1();
	AbstractClass* p2 = new ConcreteClass2();
	p1->TemplateMethod();
	p2->TemplateMethod();
	return 0;
}