From Uncle Bob, the book "Clean Code" (the example was in Java, so this was my first java translation), I played with a refactoring example in prime numbers.
Question: How would you reorganize the following code?
There are 4 versions: UglyVersion :-), BobVersion, PeteVersion, PeteVersionClassMember. I do it for fun and hope you enjoy it :-)
class ProgramBad
{
static void Main()
{
int[] result = GeneratePrimes.generatePrimes(30);
foreach (var i in result)
Console.Write(i.ToString() + ", ");
}
}
public class GeneratePrimes
{
public static int[] generatePrimes(int maxValue)
{
if (maxValue >= 2)
{
int s = maxValue + 1;
bool[] f = new bool[s];
int i;
for (i = 0; i < s; i++)
{
f[i] = true;
}
f[0] = f[1] = false;
int j;
for (i = 2; i < Math.Sqrt(s) + 1; i++)
{
if (f[i])
{
for (j = 2 * i; j < s; j += i)
f[j] = false;
}
}
int count = 0;
for (i = 0; i < s; i++)
{
if (f[i])
count++;
}
int[] primes = new int[count];
for (i = 0, j=0;i<s ; i++)
{
if (f[i])
primes[j++] = i;
}
return primes;
} else
return new int[0];
}
}
Implemented version of Bob:
class ProgramBob
{
static void Main()
{
int[] result = PrimeGeneratorBob.generatePrimes(30);
foreach (var i in result)
Console.Write(i + ", ");
}
}
class PrimeGeneratorBob
{
static bool[] crossedOut;
static int[] result;
static public int[] generatePrimes(int maxValue)
{
if (maxValue < 2)
return new int[0];
else
{
uncrossIntegersUpTo(maxValue);
crossOutMultiples();
putUncrossedIntegersIntoResult();
return result;
}
}
static void uncrossIntegersUpTo(int maxValue)
{
crossedOut = new bool[maxValue + 1];
for (int i = 2; i < crossedOut.Length; i++)
crossedOut[i] = false;
}
static void crossOutMultiples()
{
int limit = determineIterationLimit();
for (int i = 2; i <= limit; i++)
if (notCrossed(i))
crossOutMultiplesOf(i);
}
static int determineIterationLimit()
{
double iterationLimit = Math.Sqrt(crossedOut.Length);
return (int) iterationLimit;
}
static void crossOutMultiplesOf(int i)
{
for (int multiple = 2*i; multiple < crossedOut.Length; multiple += i)
crossedOut[multiple] = true;
}
static bool notCrossed(int i)
{
return crossedOut[i] == false;
}
static void putUncrossedIntegersIntoResult()
{
result = new int[numberOfUncrossedIntegers()];
for (int j = 0, i = 2; i < crossedOut.Length; i++)
if (notCrossed(i))
result[j++] = i;
}
static int numberOfUncrossedIntegers()
{
int count = 0;
for (int i = 2; i < crossedOut.Length; i++)
if (notCrossed(i))
count++;
return count;
}
}
What I like about this:
- How to easily get a general idea of how the program works, for example uncrossIntegersUpTo (MaxValue); crossOutMultiples (); putUncrossedIntegersIntoResult ();
Last weekend I talked with a friend, and we came up with this version:
class PetesRefactored
{
static void MainPete()
{
PrimeGeneratorPete pg = new PrimeGeneratorPete();
int[] arrayOfPrimes = pg.generatePrimes(30);
foreach (int prime in arrayOfPrimes)
Console.Write(prime + ", ");
}
}
class PrimeGeneratorPete
{
public int[] generatePrimes(int maxValue)
{
bool[] crossedOut;
if (maxValue < 2)
return new int[0];
else
{
crossedOut = new bool[maxValue + 1];
uncrossIntegersUpTo(crossedOut);
crossOutMultiples(crossedOut);
return putUncrossedIntegersIntoResult(crossedOut);
}
}
void uncrossIntegersUpTo(bool[] crossedOut)
{
for (int i = 2; i < crossedOut.Length; i++)
crossedOut[i] = false;
}
void crossOutMultiples(bool[] crossedOut)
{
int limit = determineIterationLimit(crossedOut);
for (int i = 2; i <= limit; i++)
if (!crossedOut[i])
crossOutMultiplesOf(crossedOut, i);
}
int determineIterationLimit(bool[] crossedOut)
{
double iterationLimit = Math.Sqrt(crossedOut.Length);
return (int) iterationLimit;
}
void crossOutMultiplesOf(bool[] crossedOut, int i)
{
for (int multiple = 2*i; multiple < crossedOut.Length; multiple += i)
crossedOut[multiple] = true;
}
int[] putUncrossedIntegersIntoResult(bool[] crossedOut)
{
int[] result = new int[numberOfUncrossedIntegers(crossedOut)];
for (int j = 0, i = 2; i < crossedOut.Length; i++)
if (!crossedOut[i])
result[j++] = i;
return result;
}
int numberOfUncrossedIntegers(bool[] crossedOut)
{
int count = 0;
for (int i = 2; i < crossedOut.Length; i++)
if (!crossedOut[i])
count++;
return count;
}
}
we
- CrossOut initialized in generatePrimes instead of 'child method
- Pass to crossedOut as parameter instead of class scope variable
- (), notCrossed (i), Out [i], .
.
crossedOut . , .
class PrimeGeneratorPeteClassMember
{
bool[] crossedOut;
public int[] generatePrimes(int maxValue)
{
if (maxValue < 2)
return new int[0];
else
{
crossedOut = new bool[maxValue + 1];
uncrossIntegersUpTo();
crossOutMultiples();
return putUncrossedIntegersIntoResult();
}
}
void uncrossIntegersUpTo()
{
for (int i = 2; i < crossedOut.Length; i++)
crossedOut[i] = false;
}
void crossOutMultiples()
{
int limit = determineIterationLimit();
for (int i = 2; i <= limit; i++)
if (!crossedOut[i])
crossOutMultiplesOf(i);
}
int determineIterationLimit()
{
double iterationLimit = Math.Sqrt(crossedOut.Length);
return (int)iterationLimit;
}
void crossOutMultiplesOf(int i)
{
for (int multiple = 2 * i; multiple < crossedOut.Length; multiple += i)
crossedOut[multiple] = true;
}
int[] putUncrossedIntegersIntoResult()
{
int[] result = new int[numberOfUncrossedIntegers()];
for (int j = 0, i = 2; i < crossedOut.Length; i++)
if (!crossedOut[i])
result[j++] = i;
return result;
}
int numberOfUncrossedIntegers()
{
int count = 0;
for (int i = 2; i < crossedOut.Length; i++)
if (!crossedOut[i])
count++;
return count;
}
}