The template method pattern defines the skeleton of an algorithm in a method, deferring some steps to subclasses. Template method lets subclasses redefine certain steps of an algorithm without changing the algorithm’s structure.
According to above description, we can learn that factory method pattern is a special version of template method as it lets subclass make a decision to instantiate which class.
Taking the same example in command pattern, this time I use template pattern to implement worker class. For different workers, they have the same workflow, that is read request from master process, analyse request, excute request and return result.
// abstract worker
class Worker
{
public:
// template method, do not modify
virtual void process() final {
// hook for subclass
hook();
readRequest();
analyseRequest();
executeRequest();
returnResult();
}
void readRequest()
{
cout << "IPC: read request from master process" << endl;
}
void analyseRequest()
{
cout << "Protocol Analysis: analyse request and store result to handle" << endl;
}
virtual void executeRequest() = 0;
void returnResult()
{
cout << "Return: return result in buffer to master process" << endl;
}
virtual void hook() {}
};
// append log worker
class WorkerForLog : public Worker
{
public:
void executeRequest()
{
cout << "Execute: open file and append log" << endl;
}
};
// access database worker
class WorkerForDB : public Worker
{
public:
void executeRequest()
{
cout << "Execute: open database and read tables" << endl;
}
};
int main(int argc, const char* argv[])
{
shared_ptr<Worker> log(new WorkerForLog());
shared_ptr<Worker> db(new WorkerForDB());
log->process();
cout << endl;
db->process();
return 0;
}
// abstract worker
abstract class Worker {
// template method, do not modify
public final void process() {
// hook for subclass
hook();
readRequest();
analyseRequest();
executeRequest();
returnResult();
}
public void readRequest() {
System.out.println("IPC: read request from master process");
}
public void analyseRequest() {
System.out
.println("Protocol Analysis: analyse request and store result to handle");
}
public abstract void executeRequest();
public void returnResult() {
System.out.println("Return: return result in buffer to master process");
}
public void hook() {
}
}
// append log worker
class WorkerForLog extends Worker {
@Override
public void executeRequest() {
System.out.println("Execute: open file and append log");
}
}
// access database worker
class WorkerForDB extends Worker {
@Override
public void executeRequest() {
System.out.println("Execute: open database and read tables");
}
}
public class Template {
public static void main(String[] args) {
Worker log = new WorkerForLog();
Worker db = new WorkerForDB();
log.process();
System.out.println();
db.process();
}
}