TDD and Refactoring

1. Refactoring practice

Practice topic: Refactoring the method to obtain all prime numbers within a specified value

Unit test case:

package training.generatPrimes.test;

import static org.junit.Assert.*;

import org.junit.Test;

import training.generatPrimes.PrimeGenerator;

public class PrimeGeneratorTest {

	@Test
	public void testPrimes() {
		int[] nullArray = new PrimeGenerator().generatePrimes(0);
		assertEquals(0, nullArray.length);

		int[] minArray = new PrimeGenerator().generatePrimes(2);
		assertEquals(1, minArray.length);
		assertEquals(2, minArray[0]);

		int[] threeArray = new PrimeGenerator().generatePrimes(3);
		assertEquals(2, threeArray.length);
		assertEquals(2, threeArray[0]);
		assertEquals(3, threeArray[1]);

		int[] centArray = new PrimeGenerator().generatePrimes(100);
		assertEquals(25, centArray.length);
		assertEquals(97, centArray[24]);
	}

	@Test
	public void testExhaustive() {
		for (int i = 2; i < 500; i++) {
			verifyPrimeList(new PrimeGenerator().generatePrimes(i));
		}
	}

	private void verifyPrimeList(int[] list) {
		for (int i = 0; i < list.length; i++) {
			verifyPrime(list[i]);
		}
	}

	private void verifyPrime(int n) {
		for (int factor = 2; factor < n; factor++) {
			assertTrue(n % factor != 0);
		}
	}
}

Before refactoring:

package training.generatPrimes;

/**
 * Refactorings:
 *
 * Extract Fields.
 * Extract Methods: initArrayOfIntegers, crossOutMultiples, putUncrossedIntegerIntoResult
 * Inline s with f.length
 * Rename f to isCrossed
 * Ensure for loop starts from 2
 * Extract Methods: crossOutMultipleOf, numberOfUncrossedIntegers, notCrossed
 * Rename methods to: uncrossIntegersUpTo
 */
public class PrimeGenerator {
	/**
	 *
	 * @param maxValue
	 *            is the generation limit
	 * @return
	 */
	public int[] generatePrimes(int maxValue) {
		if (maxValue >= 2) { // the only valid case
			// declarations
			int s = maxValue + 1; // size of array
			boolean[] f = new boolean[s];

			// initialize array to true
			for (int i = 0; i < s; i++) {
				f[i] = true;
			}

			// get rid of known non-primes
			f[0] = f[1] = false;

			// sieve
			for (int i = 2; i < Math.sqrt(s) + 1; i++) {
				for (int j = 2 * i; j < s; j += i) {
					f[j] = false; // multiple is not prime
				}
			}

			// how many primes are there?
			int count = 0;
			for (int i = 0; i < s; i++) {
				if (f[i])
					count++; // bump count
			}

			int[] primes = new int[count];

			// move the primes into the result
			for (int i = 0, j = 0; i < s; i++) {
				if (f[i])
					primes[j++] = i;
			}

			return primes;
		} else { // maxValue < 2
			return new int[0]; // return null array if bad input.
		}
	}
}
After refactoring:
package training.generatPrimes;

/**
 * Refactorings:
 *
 * Extract Fields.
 * Extract Methods: initArrayOfIntegers, crossOutMultiples, putUncrossedIntegerIntoResult
 * Inline s with f.length
 * Rename f to isCrossed
 * Ensure for loop starts from 2
 * Extract Methods: crossOutMultipleOf, numberOfUncrossedIntegers, notCrossed
 * Rename methods to: uncrossIntegersUpTo
 */
public class PrimeGenerator {
	
	private boolean[] composite;
	
	/**
	 *
	 * @param maxValue
	 *            is the generation limit
	 * @return
	 */
	public int[] generatePrimes(int maxValue) {
		initArrayOfIntegers (maxValue);
		markAllMultiplesToComposite();
		return getPrimes();
	}

	/**
	 * @param maxValue
	 */
	private void initArrayOfIntegers(int maxValue) {
		composite = new boolean[maxValue + 1];
	}

	/**
	 * @return
	 */
	private int[] getPrimes() {
		int[] primes = new int[numberOfPrimes()];

		for (int i = 2, j = 0; i < composite.length; i++) {
			if (!composite[i])
				primes[j++] = i;
		}
		return primes;
	}

	/**
	 * @return
	 */
	private int numberOfPrimes() {
		int count = 0;
		for (int i = 2; i < composite.length; i++) {
			if (!composite[i])
				count++; // bump count
		}
		return count;
	}

	/**
	 * @param s
	 * @param composite
	 */
	private void markAllMultiplesToComposite() {
		for (int i = 2; i < Math.sqrt(composite.length) + 1; i++) {
			markMultiplesToComposite (i);
		}
	}

	/**
	 * @param compose
	 * @for me
	 */
	private void markMultiplesToComposite(int i) {
		for (int j = 2 * i; j < composite.length; j += i) {
			composite[j] = true; // multiple is not prime
		}
	}
}

 

2. Reconstructing theoretical knowledge

1. What kind of code needs to be refactored
1). Don't Repeat Yourself
2). Comment "Talking Code" - Wang Hongliang, the intention of commenting the code (write Why)
3). Naming naming
4). Long Method long method
 a.Performance Anxiety (performance)
   b.Scattered Code Avoidance (avoiding broken code)
   c.Rampant Growth (time urgency)
   d.Bind Conformity (team environment is a long method)
   e.Pure lgnorance (I don’t know what good code is , I don't know how to write good code)
5).Large Class
6).Dead Code
 Kill the dead: Knowledge, Expenece, Tools, Coverage ), complexity (complexity), Timing (timing)
7).Switch statuement (switch statement)
8).Inappropriate Intimacy (excessive intimacy), should adjust the other party's interface
9).Complex condition
10).Magic Number (magic number)
11). SingleTon singleton (unfavorable test)

2. Refactoring common method

1). Rename
2). Extract method
3). Inline variable
4). Invert logic
5). Move
6). Delete

3. Refactoring notes:
1) Do not change the original function
2). Run test cases frequently
3). Try to use tools
4). Based on bad code smell
5). Steps should be small
6). Only do refactoring. If there is a problem with the original logic, refactor and deal with it.

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326458711&siteId=291194637
TDD