【敏捷软件开发:原则、模式与实践】之代码重构

来源:互联网 发布:qt linux sleep头文件 编辑:程序博客网 时间:2024/04/25 21:56

  一 概念

        在Martin Fowler的名著《重构》中,他把重构定义为:在不改变代码外在行为的前提下对代码进行修改,以改进代码的内部结构的过程。

     代码实现了需求,但是代码却不精炼,冗余,结构混乱,难读懂,难维护,难扩展等等。与之相对应的一个词是"refactor",即代码重构。我们在看些外国人写的程序时可以发现,他们的代码里一般会定义大量的类、接口、方法,类与类,类与接口之间很多是继承和实现的关系,方法的代码行数很少,超过20行代码的方法不多,看他们的代码感觉最多的就是方法之间的调来调去,不像我们的代码,一个方法下来几十上百甚至两三百行都是最基本的语句构成,很少调用自己的方法。两相比较,可以看出,前者在结构上更清晰,通过类视图就可看出设计意图,并且总的代码量不会高于后者,而后者代码量庞大,代码冗余现象严重,结构不清晰,很难维护,如要修改某个错误,可能涉及到要修改的代码点很多,这样后来的维护者就很头疼了。造成这种状况的原因有这样一些:

  1.经验不足,分析设计不到位

  2.敏捷开发,虽然经验很多,但为了快速开发,没有经过分析设计

  3.缺乏意识,只为实现功能而写代码,不管代码质量

对于这样的代码,我们怎样将其变得更为精炼和易于维护呢?这就是代码重构。重构不是针对功能,纯粹是对代码本身。重构后的代码不会影响到系统的运行。

我们来看看可以在哪些方面对代码进行重构:

  1.重命名:对类,接口,方法,属性等重命名,以使得更易理解

  2.抽取代码:将方法内的一段代码抽取为另一个方法,以使得该段代码可以被其他方法调用,这是重构中很重要很常用的,此举可以极大的精炼代码,减少方法的代码行数

  3.封装字段:将类的某个字段转换成属性,可以更加合理的控制字段的访问

  4.抽取接口:将类的某些属性,方法抽取组成个接口,该类自动实现该接口

  5.提升方法内的局部变量为方法的参数:这主要是在写代码的过程中会使用到

  6.删除参数:将方法的一个或多个参数删掉

  7.重排参数:将方法的参数顺序重新排列

实际应用中,用的最多的是1、2、3,我们可以在写代码的时候有意识的运用代码重构,这样当我们完成编码时代码的质量也能得到保证。


二 代码实例
     方法功能:产生素数。
    重构前的代码:
    
/** * This class Generates prime numbers up to a user specified maximum. * the algorithm used is the Sieve of Eratosthenes. * <p> * Eratosthenes of Cyrene, b. c. 276 BC, Cyrene, Libya -- * d. c. 194, Alexandria.  The first man to calculate the circumference * of the Earth.  Also known for working on calendars with leap * years and ran the library at Alexandria. * <p> * The algorithm is quite simple.  Given an array of integers starting * at 2.  Cross out all multiples of 2.  Find the next uncrossed * integer, and cross out all of its multiples.  Repeat until * you have passed the square root of the maximum value. *  * @author Robert C. Martin * @version 9 Dec 1999 rcm */import java.util.*;/** * Class declaration *  *  * @author Robert C. Martin * @version %I%, %G% */public class GeneratePrimes{  /**   * @param maxValue is the generation limit.   */  public static int[] generatePrimes(int maxValue)  {    if (maxValue >= 2) // the only valid case    {      // declarations      int s = maxValue + 1; // size of array      boolean[] f = new boolean[s];      int i;      // initialize array to true.      for (i = 0; i < s; i++)        f[i] = true;      // get rid of known non-primes      f[0] = f[1] = false;      // sieve      int j;      for (i = 2; i < Math.sqrt(s) + 1; i++)      {        for (j = 2 * i; j < s; j += i)          f[j] = false; // multiple is not prime      }      // how many primes are there?      int count = 0;      for (i = 0; i < s; i++)      {        if (f[i])          count++; // bump count.      }      int[] primes = new int[count];      // move the primes into the result      for (i = 0, j = 0; i < s; i++)      {        if (f[i])             // if prime          primes[j++] = i;      }        return primes;  // return the primes    }    else // maxValue < 2      return new int[0]; // return null array if bad input.  }}
  重构后:
      把全部功能变成3个分离的功能。第一,对所有的变量进行初始化,并做好过滤所需要的准备工作;第二,过滤;第三,把结果放到一个整型数组中。另外去掉一些不必要的注释,并把类名改为PrimeGenerator。然后把一些函数里的局部变量提升为类级的静态变量。
 
/** * This class Generates prime numbers up to a user specified * maximum.  The algorithm used is the Sieve of Eratosthenes. * Given an array of integers starting at 2: * Find the first uncrossed integer, and cross out all its * multiples.  Repeat until there are no more multiples * in the array. */public class PrimeGenerator{  private static boolean[] crossedOut;  private static int[] result;  public static int[] generatePrimes(int maxValue)  {    if (maxValue < 2)      return new int[0];    else    {      uncrossIntegersUpTo(maxValue);      crossOutMultiples();      putUncrossedIntegersIntoResult();      return result;    }  }  private static void uncrossIntegersUpTo(int maxValue)  {    crossedOut = new boolean[maxValue + 1];    for (int i = 2; i < crossedOut.length; i++)      crossedOut[i] = false;  }  private static void crossOutMultiples()  {    int limit = determineIterationLimit();    for (int i = 2; i <= limit; i++)      if (notCrossed(i))        crossOutMultiplesOf(i);  }  private static int determineIterationLimit()  {    // Every multiple in the array has a prime factor that    // is less than or equal to the root of the array size,    // so we don't have to cross of multiples of numbers    // larger than that root.    double iterationLimit = Math.sqrt(crossedOut.length);    return (int) iterationLimit;  }  private static void crossOutMultiplesOf(int i)  {    for (int multiple = 2*i;         multiple < crossedOut.length;         multiple += i)      crossedOut[multiple] = true;  }  private static boolean notCrossed(int i)  {    return crossedOut[i] == false;  }  private static void putUncrossedIntegersIntoResult()  {    result = new int[numberOfUncrossedIntegers()];    for (int j = 0, i = 2; i < crossedOut.length; i++)      if (notCrossed(i))        result[j++] = i;  }  private static int numberOfUncrossedIntegers()  {    int count = 0;    for (int i = 2; i < crossedOut.length; i++)      if (notCrossed(i))        count++;    return count;  }}




0 0
原创粉丝点击