What is template method in C++
Intent
- Do not duplicate code among child classes
Explain
Usually, child classes provide different features with the similar code. Code 1 shows how multiple child classes are implemented.
// 01_C_AlgorithmAmongClasses.cpp
#include <iostream>
#include <vector>
using namespace std;
class BaseClass
{
public:
virtual void foo()
{
cout << "Mutex lock" << endl;
cout << "Foo for Base class" << endl;
cout << "Mutex unlock" << endl;
}
};
class DerivedClassFirst : public BaseClass
{
public:
virtual void foo()
{
cout << "Mutex lock" << endl;
cout << "Foo for First derived class" << endl;
cout << "Mutex unlock" << endl;
}
};
class DerivedClassSecond : public BaseClass
{
public:
virtual void foo()
{
cout << "Mutex lock" << endl;
cout << "Foo for Second derived class" << endl;
cout << "Mutex unlock" << endl;
}
};
int main()
{
vector<BaseClass*> v;
v.push_back(new BaseClass);
v.push_back(new DerivedClassFirst);
v.push_back(new DerivedClassSecond);
for(BaseClass* p : v)
{
p->foo();
}
return 0;
}
// Compile: clang++ -std=c++14
// -o 01_C_AlgorithmAmongClasses 01_C_AlgorithmAmongClasses.cpp
Mutex lock
Foo for Base class
Mutex unlock
Mutex lock
Foo for First derived class
Mutex unlock
Mutex lock
Foo for Second derived class
Mutex unlock
The implementation of BaseClass, DerivedClassFirst and DerivedClassSecond are very similar to each other, but only the second output lines are different. The first and third lines are duplicated among the classes. In this case, if we want to change the first or the third line, we should visit each classes. However, Don't Repeat Your code(DRY) is one of refactoring rules. Therefore, we will remove the duplicated code.
To remove the duplicated code, it is necessary to distinguish unchangeable part and changeable part. In Code 1, unchangeable part is the first and third lines. The changeable part in Code 1 is the second line. Each class has its own second line.
After distinction, unchangeable part should be move to a non virtual function of the parent class. A non virtual function is common part of all child classes, so it might be a good entrance.
This is templace method pattern (or Non Virtual Interface(NVI)), and Code 2 shows how to implement it.
// 02_C_TemplateMethod.cpp
#include <iostream>
#include <vector>
using namespace std;
class BaseClass
{
public:
void foo()
{
cout << "Mutex lock" << endl;
fooImpl();
cout << "Mutex unlock" << endl;
}
protected:
virtual void fooImpl()
{
cout << "Foo for Base class" << endl;
}
};
class DerivedClassFirst : public BaseClass
{
public:
virtual void fooImpl() override
{
cout << "Foo for First derived class" << endl;
}
};
class DerivedClassSecond : public BaseClass
{
public:
virtual void fooImpl() override
{
cout << "Foo for Second derived class" << endl;
}
};
int main()
{
vector<BaseClass*> v;
v.push_back(new BaseClass);
v.push_back(new DerivedClassFirst);
v.push_back(new DerivedClassSecond);
for(BaseClass* p : v)
{
p->foo();
}
return 0;
}
// Compile: clang++ -std=c++14
// -o 02_C_TemplateMethod 02_C_TemplateMethod.cpp
Mutex lock
Foo for Base class
Mutex unlock
Mutex lock
Foo for First derived class
Mutex unlock
Mutex lock
Foo for Second derived class
Mutex unlock
The non virtual function, foo() includes the first line and the third line of Code 1. Also, each class has its virtual function, fooImpl(), and the function includes the second line of Code 1. As a result, the result of Code 1 and Code 2 are the same, but there is no duplicated code.
Normally, algorithm is unchangeable part. The first and third lines are used to prepare for or finish the actual work, the second line. So, they are necessary common step, and part of algorithm. Therefore, they are included in the parent class.
Summary
- Template method pattern is to implement unchangeable part in parent class and implement changeable part in child class.
- Algorithm is unchangeable part, so it is implemented in the parent class.
COMMENTS