Поиск…


Вступление

Рефакторинг относится к модификации существующего кода в улучшенную версию. Хотя рефакторинг часто выполняется при смене кода для добавления функций или исправления ошибок, термин, в частности, означает улучшение кода без необходимости добавления функций или исправления ошибок.

Рефакторинг проходит

Вот программа, которая может помочь в рефакторинге. Это простая программа, использующая C ++ 11, которая предназначена для вычисления и печати всех простых чисел от 1 до 100 и основана на программе, которая была отправлена ​​на CodeReview для обзора.

#include <iostream>
#include <vector>
#include <cmath>

int main()
{
    int l = 100;
    bool isprime;
    std::vector<int> primes;
    primes.push_back(2);
    for (int no = 3; no < l; no += 2) {
        isprime = true;
        for (int primecount=0; primes[primecount] <= std::sqrt(no); ++primecount) {
            if (no % primes[primecount] == 0) {
                isprime = false;
                break;
            } else if (primes[primecount] * primes[primecount] > no) {
                std::cout << no << "\n";
                break;
            }
        }
        if (isprime) {
            std::cout << no << " ";
            primes.push_back(no);
        }
    }
    std::cout << "\n";
}

Результат этой программы выглядит следующим образом:

3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97

Первое, что мы замечаем, это то, что программе не удается напечатать 2 что является простым числом. Мы могли бы просто добавить строку кода, чтобы просто напечатать одну константу без изменения остальной части программы, но может быть более аккуратно реорганизовать программу, чтобы разбить ее на две части: одну, которая создает список простых чисел, другой, который их печатает , Вот как это может выглядеть:

#include <iostream>
#include <vector>
#include <cmath>

std::vector<int> prime_list(int limit)
{
    bool isprime;
    std::vector<int> primes;
    primes.push_back(2);
    for (int no = 3; no < limit; no += 2) {
        isprime = true;
        for (int primecount=0; primes[primecount] <= std::sqrt(no); ++primecount) {
            if (no % primes[primecount] == 0) {
                isprime = false;
                break;
            } else if (primes[primecount] * primes[primecount] > no) {
                break;
            }
        }
        if (isprime) {
            primes.push_back(no);
        }
    }
    return primes;
}

int main() 
{
    std::vector<int> primes = prime_list(100);
    for (std::size_t i = 0; i < primes.size(); ++i) {
        std::cout << primes[i] << ' ';
    }
    std::cout << '\n';
}

Попытка этой версии, мы видим, что она действительно работает правильно сейчас:

2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97

Следующий шаг - заметить, что предложение second if действительно не требуется. Логика в цикле ищет простые коэффициенты каждого заданного числа до квадратного корня из этого числа. Это работает, потому что, если есть какие-либо простые множители числа, по крайней мере один из них должен быть меньше или равен квадратному корню из этого числа. Перерабатывая только эту функцию (остальная часть программы остается прежней), мы получаем следующий результат:

std::vector<int> prime_list(int limit)
{
    bool isprime;
    std::vector<int> primes;
    primes.push_back(2);
    for (int no = 3; no < limit; no += 2) {
        isprime = true;
        for (int primecount=0; primes[primecount] <= std::sqrt(no); ++primecount) {
            if (no % primes[primecount] == 0) {
                isprime = false;
                break;
            }
        }
        if (isprime) {
            primes.push_back(no);
        }
    }
    return primes;
}

Мы можем идти дальше, изменяя имена переменных, чтобы быть более подробными. Например, primecount самом деле не является числом простых чисел. Вместо этого это переменная индекса в вектор известных простых чисел. Кроме того, в то время как no иногда используется как аббревиатура для «числа», в математическом письме чаще используется n . Мы также можем внести некоторые изменения, устранив break , и объявив переменные ближе к тому, где они используются.

std::vector<int> prime_list(int limit)
{
    std::vector<int> primes{2};
    for (int n = 3; n < limit; n += 2) {
        bool isprime = true;
        for (int i=0; isprime && primes[i] <= std::sqrt(n); ++i) {
            isprime &= (n % primes[i] != 0);
        }
        if (isprime) {
            primes.push_back(n);
        }
    }
    return primes;
}

Мы можем также реорганизовать main использовать «спектр-за» , чтобы сделать его немного аккуратнее:

int main() 
{
    std::vector<int> primes = prime_list(100);
    for (auto p : primes) {
        std::cout << p << ' ';
    }
    std::cout << '\n';
}

Это всего лишь один способ рефакторинга. Другие могут делать разные варианты. Тем не менее, цель рефакторинга остается той же, которая заключается в улучшении читаемости и, возможно, производительности кода без необходимости добавления функций.

Goto Cleanup

В базовых кодах C ++, которые раньше были C, можно найти goto cleanup шаблона goto cleanup . Поскольку команда goto делает рабочий процесс функции сложнее понять, этого часто избегают. Часто он может быть заменен операторами return, циклами, функциями. Хотя с goto cleanup нужно избавиться от логики очистки.

short calculate(VectorStr **data) {
    short result = FALSE;
    VectorStr *vec = NULL;
    if (!data)
       goto cleanup;  //< Could become return false

    // ... Calculation which 'new's VectorStr

    result = TRUE;
cleanup:
    delete [] vec;
    return result;
}

В C ++ для устранения этой проблемы можно использовать RAII :

struct VectorRAII final {
    VectorStr *data{nullptr};
    VectorRAII() = default;
    ~VectorRAII() {
        delete [] data;
    }
    VectorRAII(const VectorRAII &) = delete;
};

short calculate(VectorStr **data) {
    VectorRAII vec{};
    if (!data)
       return FALSE;  //< Could become return false

    // ... Calculation which 'new's VectorStr and stores it in vec.data

    return TRUE;
}

С этого момента можно продолжить рефакторинг фактического кода. Например, заменив VectorRAII на std::unique_ptr или std::vector .



Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow