Refactor Template Method to Template Function

  
OOP中,Template Method模式的一个典型实现如下: 
 
class AbstractTestCase
{
public:
  AbstractTestCase(std::string
const& testName)
    : testName_(testName)
  {}
   
 
void RunTest()
  {
    Logger::Instance().Log(
"Start Test: " + testName_);
   
try
    {
      RunTestImpl();
    }
   
catch(std::exception& e)
    {
      Logger::Instance().Log(
"Exception: " + e.what());
    }
   
catch(...)
    {
      Logger::Instance().Log(
"Unknown Exception");
    }
    Logger::Instance().Log(
"End Test: " + testName_);
  }
 
private:
  std::string testName_;
 
virtual void RunTestImpl() = 0;
};
 
class ConcreteTestCase1 : public AbstractTestCase
{
public:
  ConcreteTestCase1()
    : AbstractTestCase(
"ConcreteTestCase1")
  {}
 
private:
 
virtual void RunTestImpl()
  {
  ...
  }
}
... // other ConcreteTestCase that derives from AbstractTestCase
 
int main()
{
  std::vector<AbstractTestCase*> testCases;
  testCases.push_back(
new ConcreteTestCase1);
  testCases.push_back(
new ConcreteTestCase2);
  ...
 
 
for(int i=0; i<testCases.size(); ++i)
  {
    testCases[i]->RunTest();
  }
 
 
return 0;
}
 
以上是一个简单的测试框架。其中Logger是一个Singleton对象,它把测试过程中收集的信息写入日志,以便日后分析。
RunTest()RunTestImpl()Template Method的实作,所有的ConcreteTestCase复用了RunTest()的流程。
C++Template Function也可以实现流程的复用,于是上述代码可以改写为:
 
template <typename Function>
void RunTest(std::string const& testName, Function test) 
{
  Logger::Instance().Log(
"Start Test: " + testName);
 
try
  {
    test();
  }
 
catch(std::exception& e)
  {
    Logger::Instance().Log(
"Exception: " + e.what());
  }
 
catch(...)
  {
    Logger::Instance().Log(
"Unknown Exception");
  }
  Logger::Instance().Log(
"End Test: " + testName);
}
 
void test1()
{
  ...
}
 
void test2()
{
  ...
}
 
int main()
{
 
RunTest("test1", test1);
  RunTest("test2", test2);
  
 
return 0;
}
 
这个例子只是想说明,如果不需要OOP的动态接口复用,只需要静态代码复用,那么Template Function是一种很方便的选择。此外,配合使用Boost.Bind (它将成为C++09标准库的一部分),我们可以获得额外的弹性。例如,您的TestCase希望从数据文件中读取测试数据,这将有利于您逐步完善测试数据。此外,您也不愿意把测试数据文件的路径写死在测试代码中,这样您可以在不同的时刻使用不同的测试数据集。这时,您可以这样构建您的测试程序。
 
#include "boost/bind.hpp"
...
 
void testWithFile(char const* filePath)
{
  ...
}
 
int main(int argc, char* argv[])
{
 
// Smoking tests that should be run every time
  RunTest("test1", test1);
  RunTest("test2", test2);
 
  if(2 == argc)
  {
    // Load test file whose path is in argv[1]
    RunTest("testWithFile", boost::bind(testWithFile, argv[1]));
  }
 
return 0;
}
 
实际上,利用Boost.Function (它也将成为C++09标准库的一部分),我们甚至可以将RunTest()重构为普通函数 (Refactor Template Function to Trivial Function with Generic Delegate)
 
#include "boost/bind.hpp" 
#include "boost/function.hpp"
 
void RunTest(std::string const& testName,
             boost::function0<void> const& test) 
{
  Logger::Instance().Log(
"Start Test: " + testName);
 
try
  {
    test();
  }
 
catch(std::exception& e)
  {
    Logger::Instance().Log(
"Exception: " + e.what());
  }
 
catch(...)
  {
    Logger::Instance().Log(
"Unknown Exception");
  }
  Logger::Instance().Log(
"End Test: " + testName);
}
 
...
 
int main(int argc, char* argv[])
{
 
// Smoking tests that should be run every time
  RunTest("test1", test1);
  RunTest("test2", test2);
 
  if(2 == argc)
  {
    // Load test file whose path is in argv[1]
    RunTest("testWithFile", boost::bind(testWithFile, argv[1]));
  }
 
return 0;
}
 
这个简单的例子表明,C++ Template Metaprogramming将通过程序库来影响我们的编程方式。
原文地址:https://www.cnblogs.com/liangshi/p/1722860.html