开发者

C++ refactor common code with one different statement

开发者 https://www.devze.com 2023-01-02 04:47 出处:网络
I have two methods f(vector<int>& x, ....) and g(DBConn& x, ....) where the (....)parameters are all identical.

I have two methods f(vector<int>& x, ....) and g(DBConn& x, ....) where the (....) parameters are all identical.

The code inside the two methods are completely identical except for one statement where we do different actions based on the type of x:

in 开发者_如何学JAVAf(): we do x.push_back(i)
in g(): we do x.DeleteRow(i)

What is the simplest way to extract the common code into one method and yet have the two different statements?

I am thinking of having a templated functor that overloads operator () (int a) but that seems overkill.


common_function(....)
{
}

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


You could write a simple adapter with two implementations, each calling the desired method of a different class.

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); }
}


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);
  ...
}

OR:

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);
  ...
}

NOTE: I might have some syntax wrong but you get the idea.


Yet another idea:

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, ...);
}


Classic case for a functor:

#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);
}


You could make a function that has the parameters of what you call (...), and this function can implement the logic that is the same in f() and g(). You could then change the implementation of f() and g() to call this new function instead of duplicating the logic. Be careful though if you're doing something duplicated before and after your unique lines. You may need two functions in that case. At any rate I think this would be preferable to having duplicated blocks of code.

0

精彩评论

暂无评论...
验证码 换一张
取 消