Осуществите рефакторинг следующие два метода C++ для выезда дублирующего кода

У меня есть следующие два метода, которые (как Вы видите) похожи в большинстве его операторов за исключением одного (см. ниже для деталей),

unsigned int CSWX::getLineParameters(const SURFACE & surface, vector<double> & params)
{
    VARIANT varParams;

    surface->getPlaneParams(varParams); // this is the line of code that is different

    SafeDoubleArray sdParams(varParams);

    for( int i = 0 ;  i < sdParams.getSize() ; ++i )
    {
        params.push_back(sdParams[i]);
    }

    if( params.size() > 0 ) return 0;
    return 1;
}

unsigned int CSWX::getPlaneParameters(const CURVE & curve, vector<double> & params)
{
    VARIANT varParams;

    curve->get_LineParams(varParams); // this is the line of code that is different

    SafeDoubleArray sdParams(varParams);

    for( int i = 0 ;  i < sdParams.getSize() ; ++i )
    {
        params.push_back(sdParams[i]);
    }

    if( params.size() > 0 ) return 0;
    return 1;
}

Есть ли какая-либо техника, которую я могу использовать для перемещения общих строк кода этих двух методов к отдельному методу, который можно было назвать от этих двух изменений - ИЛИ - возможно комбинируют эти два метода к отдельному методу?

Следующее является ограничениями:

  1. Классы ПОВЕРХНОСТЬ и КРИВАЯ из сторонних библиотек и следовательно немодифицируемые. (Если помогает, что они оба получены из IDispatch),
  2. Существуют еще более подобные классы (например, Поверхность), который мог вписаться в этот "шаблон" (не шаблон C++, просто поток строк кода)

Я знаю, что следующее могло (возможно?) быть реализованным как решения, но действительно надеюсь, что существует лучшее решение:

  1. Я мог добавить 3-й параметр к этим 2 методам - например, перечисление - который определяет 1-й параметр (например, перечисление:: input_type_surface, перечисление:: input_type_curve)
  2. Я мог передать в IDispatch и попробовать dynamic_cast <> и тест, которые бросают, NON_NULL, и сделайте, если еще назвать правильный метод (например, getPlaneParams () по сравнению с get_LineParams ())

Следующее не является ограничением, но было бы требованием из-за моего сопротивления товарищей по команде:

  1. Не реализуют новый класс, который наследовался ПОВЕРХНОСТИ/КРИВОЙ и т.д. (Они очень предпочли бы решать ее с помощью перечислимого вышеизложенного решения I),
8
задан ossandcad 29 March 2010 в 17:08
поделиться

5 ответов

На ум приходит пара идей, но вот то, что я думаю, было бы лучше всего:

namespace detail
{
    void getParameters(const SURFACE& surface, VARIANT& varParams)
    {
        surface->getPlaneParams(varParams);
    }

    void getParameters(const CURVE& curve, VARIANT& varParams)
    {
        curve->get_LineParams(varParams);
    }
}

template <typename T>
unsigned int getParameters(const T& curve, vector<double> & params)
{
    VARIANT varParams;
    detail::getParameters(curve, varParams);

    SafeDoubleArray sdParams(varParams);
    for( int i = 0 ;  i < sdParams.getSize() ; ++i )
    {
        params.push_back(sdParams[i]);
    }

    return params.size() != 0;
}

Вы делегируете задачу получения параметров какой-либо другой перегруженной функции. Просто добавьте такие функции для каждого типа, который у вас есть. (Обратите внимание, я упростил ваше выражение возврата.)

11
ответ дан 5 December 2019 в 10:40
поделиться

Почему бы просто не передать ВАРИАНТ varParams в качестве параметра функции вместо КРИВОЙ или SURFACE ?

unsigned int CSWX::getParameters(VARIANT varParams, vector<double> & params)
{
    SafeDoubleArray sdParams(varParams);

    for( int i = 0 ;  i < sdParams.getSize() ; ++i )
    {
        params.push_back(sdParams[i]);
    }

    if( params.size() > 0 ) return 0;
    return 1;
}

unsigned int CSWX::getPlaneParameters(const CURVE & curve, vector<double> & params)
{
    VARIANT varParams;    

    curve->get_LineParams(varParams); // this is the line of code that is different

    return getParameters( varParams, params );
}

Вы также можете рассмотреть (если возможно) создание этих шаблонов методов и получить output_iterator в качестве параметра вместо вектора . Таким образом, ваш код не зависит от типа используемой коллекции.

2
ответ дан 5 December 2019 в 10:40
поделиться

Метод извлечения. Все после строк, которые вы отметили как разные, идентично - поэтому извлеките их как метод, который вызывается из обоих ваших исходных методов.

5
ответ дан 5 December 2019 в 10:40
поделиться

Вместо передачи SURFACE или CURVE передайте ссылку на базовый класс, а также указатель на функцию метода. Тогда вызов функции surface-> getLine_parameters или curve-> getPlaneParamters будет заменен на (shape -> * getParamters) (varParams);

typedef void Baseclass::*ParamGetter(VARIANT varParams);

unsigned int CSWX::getLineParameters(const Baseclass & geometry, ParamGetter getParams
       vector<double> & params)
{
  VARIANT varParams;

  (geometry->*getParams)(varParams); // this is the line of code that is different

  SafeDoubleArray sdParams(varParams);

  for( int i = 0 ;  i < sdParams.getSize() ; ++i )
  {
      params.push_back(sdParams[i]);
  }

  if( params.size() > 0 ) return 0;
  return 1;
}
0
ответ дан 5 December 2019 в 10:40
поделиться

Macro! Обычно это не лучшее решение (это макрос) и, вероятно, не самое лучшее в этом, но оно сработает.

macro_GetDakine_Params(func)
    VARIANT varParams; \
    curve->##func(varParams); // this is the line of code that is different \
    SafeDoubleArray sdParams(varParams); \
    for( int i = 0 ;  i < sdParams.getSize() ; ++i ) \
    { \
        params.push_back(sdParams[i]); \
    } \
    if( params.size() > 0 ) return 0; \
    return 1; \

unsigned int CSWX::getPlaneParameters(const CURVE & curve, vector<double> & params)
{
    macro_GetDakine_Params(getPlaneParams)
}
unsigned int CSWX::getLineParameters(const CURVE & curve, vector<double> & params)
{
    macro_GetDakine_Params(getLineParams)
}
-2
ответ дан 5 December 2019 в 10:40
поделиться
Другие вопросы по тегам:

Похожие вопросы: