zoukankan      html  css  js  c++  java
  • 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将通过程序库来影响我们的编程方式。
  • 相关阅读:
    tp5更改入口文件到根目录的方法分享
    Linux安装JBOSS
    JBOSS和WebLogic区别
    面向对象编程的思维方式
    Struts+Spring+Hibernate整合入门详解
    DB2 UDB V8.1 管理
    oracle与DB2的一些架构
    oracle和DB2的差异
    JDK和JRE的区别
    Linux安装weblogic
  • 原文地址:https://www.cnblogs.com/liangshi/p/1722860.html
Copyright © 2011-2022 走看看