Refactor Template Method to Template Function

OOP中,Template Method模式的一个典型实现如下:classAbstractTestCase

{

public:

AbstractTestCase(std::string
const& testName)

: testName_(testName)

{}



voidRunTest()

{

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 voidRunTestImpl() = 0;

};
classConcreteTestCase1 :publicAbstractTestCase

{

public:

ConcreteTestCase1()

: AbstractTestCase(
"ConcreteTestCase1")

{}



private:

virtual voidRunTestImpl()

{

...

}

}
...// other ConcreteTestCase that derives from AbstractTestCaseintmain()

{

std::vector testCases;

testCases.push_back(
newConcreteTestCase1);

testCases.push_back(
newConcreteTestCase2);

...



for(inti=0; i\
{\
\
testCases[i]->RunTest();

}



return0;

}
以上是一个简单的测试框架。其中Logger是一个Singleton对象,它把测试过程中收集的信息写入日志,以便日后分析。RunTest()RunTestImpl()Template Method的实作,所有的ConcreteTestCase复用了RunTest()的流程。C++Template Function也可以实现流程的复用,于是上述代码可以改写为:template<typenameFunction>voidRunTest(std::stringconst&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);

}
voidtest1(){...

}
voidtest2(){...}intmain()

{

RunTest("test1", test1);RunTest("test2", test2);



return0;

}
这个例子只是想说明,如果不需要OOP的动态接口复用,只需要静态代码复用,那么Template Function是一种很方便的选择。此外,配合使用Boost.Bind(它将成为C++09标准库的一部分),我们可以获得额外的弹性。例如,您的TestCase希望从数据文件中读取测试数据,这将有利于您逐步完善测试数据。此外,您也不愿意把测试数据文件的路径写死在测试代码中,这样您可以在不同的时刻使用不同的测试数据集。这时,您可以这样构建您的测试程序。#include"boost/bind.hpp"...voidtestWithFile(char const filePath){...}intmain(intargc,char argv[])

{

// Smoking tests that should be run every timeRunTest("test1", test1);RunTest("test2", test2);if(2 == argc){// Load test file whose path is in argv[1]RunTest("testWithFile", boost::bind(testWithFile, argv[1]));}

return0;

}
实际上,利用Boost.Function(它也将成为C++09标准库的一部分),我们甚至可以将RunTest()重构为普通函数(Refactor Template Function to Trivial Function with Generic Delegate)#include"boost/bind.hpp"#include"boost/function.hpp"voidRunTest(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);

}
...intmain(intargc,char* argv[])

{

// Smoking tests that should be run every timeRunTest("test1", test1);RunTest("test2", test2);if(2 == argc){// Load test file whose path is in argv[1]RunTest("testWithFile", boost::bind(testWithFile, argv[1]));}

return0;

}
这个简单的例子表明,C++ Template Metaprogramming将通过程序库来影响我们的编程方式。原文链接: https://www.cnblogs.com/liangshi/archive/2010/04/28/1722860.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/10464

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月6日 下午11:45
下一篇 2023年2月6日 下午11:45

相关推荐