【问题标题】:C++ refactor common code with one different statementC++ 用一种不同的语句重构公共代码
【发布时间】:2011-02-26 20:21:01
【问题描述】:

我有两种方法f(vector<int>& x, ....) and g(DBConn& x, ....) 其中 (....) 参数都是相同的。

这两种方法中的代码除了一个语句外完全相同 我们根据 x 的类型执行不同的操作:

in f(): we do x.push_back(i)
in g(): we do x.DeleteRow(i)

将通用代码提取到一种方法中的最简单方法是什么? 有两种不同的说法吗?

我正在考虑使用一个模板化的仿函数来重载运算符 () (int a),但这似乎有点过头了。

【问题讨论】:

  • 两者的代码是否会发生不同的演变?如果是这样,请保持原样,因为它们的相似性纯属巧合。

标签: c++ refactoring common-code


【解决方案1】:
common_function(....)
{
}

f(vector<int>x,... )
{
    x.push_back(i);
    common_f(...);
}
g(DBConn& x, ....)
{
    x.DeleteRow(i);
    common_f(...);
}

【讨论】:

  • 这可能有效,但我需要以下格式:common_g() x.push_back(i) common_f() 没那么简单。
  • 另外,您还有一组(或两组)参数推送。
【解决方案2】:

您可以编写一个具有两个实现的简单适配器,每个实现调用不同类的所需方法。

class MyInterface {
public:
  virtual doIt(int i) = 0;
}

class VectorImp : public MyInterface {
public:
  vector<int>& v;
  VectorImp(vector<int>& theVector) : v(theVector) {}
  doIt(int i) { x.push_back(i); }
}

class DbImp : public MyInterface {
public:
  DBConn& c;
  VectorImp(DBConn& conn) : c(conn) {}
  doIt(int i) { c.DeleteRow(i); }
}

【讨论】:

  • 我更喜欢这个而不是模板有两个原因。首先,它只会为 f/g 函数的一个实例生成编译代码,模板通常会为每个模板实例化生成编译代码。其次,我将模板视为“无论类型如何都做同样的事情”,但这是“根据类型做不同的事情”。
  • 我不打算这样做,因为它通过虚函数调用添加了下一级间接。但它仍然是有效的解决方案。
  • @Tomek,现实生活中的解决方案始终是一种权衡:-)
【解决方案3】:
template<class T>
struct Adapter;

template<>
struct Adapter<vector<int> >
{
  static void execute(vector<int> &x, int i)
  {
    x.push_back(i);
  }
};

template<>
struct Adapter<DBConn>
{
  static void execute(DBConn &x, int i)
  {
    v.DeleteRow(i);
  }
};

template<class T>
void f(T &t, ...)
{
  ...
  Adapter<T>::execute(t, i);
  ...
}

或者:

template<class T>
struct adapter_traits;

template<>
struct adapter_traits<vector<int> >
{
  typedef void (vector<int>::*PMF)(int);
  static const PMF pmf = &vector<int>::push_back;
}

template<>
struct adapter_traits<DBConn>
{
  typedef void (DBConn::*PMF)(int);
  static const PMF pmf = &DBConn::DeleteRow;
}

template<class T>
void f(T &t, ...)
{
  ...
  (t.*adapter_traits<T>::pmf)(i);
  ...
}

注意:我可能有一些语法错误,但你明白了。

【讨论】:

    【解决方案4】:

    还有一个想法:

    template<class T>
    void f(T &t, void (T::*p)(int), ...)
    {
      ...
      (t.*p)(i);
    }
    
    void g()
    {
      DBConn x;
      vector<int> y;
      f(x, &DBConn::DeleteRow, ...);
      f(y, &vector<int>::push_back, ...);
    }
    

    【讨论】:

      【解决方案5】:

      函子的经典案例:

      #include <vector>
      #include <DBConn.h>
      
      // T:    The type of the object that is to be manipulated.
      // A:    The type of the object that will do the manipulating
      //       This may be a functor object or a function pointer.
      //
      // As this is a template function the template parameters will
      // be deduced by the compiler at compile time.
      template<typename T,typename A>
      void action(T& obj,A const& action/*,....*/)
      {
          // Do Stuff
          action(obj,5);
          // Do more Stuff
      }
      
      // Functor object
      struct MyVectorAction
      {
          // Just defines the operator()
          // Make sure it is a const method.
          // This does the unique bit of code. The parameters should be what you pass into action
          void operator()(std::vector<int>& data,int val) const   {data.push_back(val);}
      };
      void f(std::vector<int>& x)
      {
          action(x,MyVectorAction()/*.... Params ....*/);
      }
      
      
      struct MyDBConnAction
      {   void operator()(DBConn& data,int val) const   {data.DeleteRow(val);} };
      void g(DBConn& x)
      {
          action(x, MyDBConnAction());
      }
      
      int main()
      {
          std::vector<int>    x;
      
          f(x);
      }
      

      【讨论】:

      • 使用 C++0x 和 lambdas 会更好...你可能可以避免使用仿函数。
      【解决方案6】:

      你可以创建一个函数,它有你调用的参数(...),这个函数可以实现f()和g()中相同的逻辑。然后,您可以更改 f() 和 g() 的实现来调用这个新函数,而不是复制逻辑。但是,如果您在独特的线条之前和之后做重复的事情,请小心。在这种情况下,您可能需要两个函数。无论如何,我认为这比重复的代码块更可取。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-04-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-02-16
        • 2020-03-14
        相关资源
        最近更新 更多