重構走過
這是一個可能受益於重構的程式。這是一個使用 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
下一步是要注意第二個 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
以使用“range-for”來使它更整潔:
int main()
{
std::vector<int> primes = prime_list(100);
for (auto p : primes) {
std::cout << p << ' ';
}
std::cout << '\n';
}
這只是重構的一種方式。其他人可能做出不同的選擇但是,重構的目的仍然是相同的,這是為了提高程式碼的可讀性和可能性,而不必新增功能。