重构是指在不改变程序功能的前提下改变其结构。重构是一项功能强大的技术,但是执行起来需要倍加小心才行。主要的危险在于可能在不经意中引入一些错误,尤其是在进行手工重构的时候更是如此。这种危险引发了对重构技术的普遍批评:当代码不会崩溃的时候为什么要修改它呢?
您需要进行代码重构的原因可能有以下几个:传说中的第一个原因是:需要继承为某个古老产品而开发的年代久远的代码,或者突然碰到这些代码。最初的开发团队已经不在了。我们必须创建增加了新特性的新版本软件,但是这些代码已经无法理解了。新的开发队伍夜以继日地工作,破译代码然后映射代码,经过大量的规划与设计之后,人们将这些代码分割成碎片。历经重重磨难之后,所有这些东西都按照新版本的要求归位了。这是英雄般的重构故事,几乎没有人能在经历了这些之后活着讲述这样的故事。
还有一种现实一些的情况是项目中加入了新的需求,需要对设计进行修改。至于是因为在最初的规划过程中失察,还是由于采用了迭代式的开发过程(比如敏捷开发,或者是测试驱动的开发)而在开发过程中有意引入需求,这两者并没有实质性的区别。这样的重构的规模要小得多,其内容一般涉及通过引入接口或者抽象类来更改类的继承关系,以及对类进行分割和重新组织,等等。
重构的最后一个原因是,当存在可用的自动重构工具时,可以有一个用来预先生成代码的快捷方式——就好比在您无法确定如何拼写某个单词的时候,可以用某种拼写检查工具输入这个单词。比如说,您可以用这种平淡无奇的重构方法生成 getter 和 setter 方法,一旦熟悉了这样的工具,它就可以为您节省很多的时间。
Eclipse 的重构工具无意进行英雄级的重构——适合这种规模的工具几乎没有——但是不论是否用到敏捷开发技术,Eclipse 的工具对于一般程序员修改代码的工作都具有无法衡量的价值。毕竟任何复杂的操作只要能够自动进行,就可以不那么烦闷了。只要您知道 Eclipse 实现了什么样的重构工具,并理解了它们的适用情况,您的生产力就会得到极大的提高。
要降低对代码造成破坏的风险,有两种重要的方法。第一种方法是对代码进行一套完全彻底的单元测试:在重构之前和之后都必须通过这样的测试。第二种方法是使用自动化的工具来进行重构,比如说 Eclipse 的重构特性。
将彻底的测试与自动化重构结合起来就会更加有效了,这样重构也就从一种神秘的艺术变成了有用的日常工具。为了增加新的功能或者改进代码的可维护性,我们可以在不影响原有代码功能的基础上迅速且安全地改变其结构。这种能力会对您设计和开发代码的方式产生极大的影响,即便是您没有将其结合到正式的敏捷方法中也没有关系。
Eclipse 的重构工具可以分为三大类(下面的顺序也就是这些工具在 Refactoring 菜单中出现的顺序):
- 对代码进行重命名以及改变代码的物理结构,包括对属性、变量、类以及接口重新命名,还有移动包和类等。
- 改变类一级的代码逻辑结构,包括将匿名类转变为嵌套类,将嵌套类转变为顶级类、根据具体的类创建接口,以及从一个类中将方法或者属性移到子类或者父类中。
- 改变一个类内部的代码,包括将局部变量变成类的属性、将某个方法中选中部分的代码变成一个独立的方法、以及为属性生成 getter 和 setter 方法。
还有几个重构工具并不能完全归入这三个种类,特别是 Change Method Signature,不过在本文中还是将这个工具归入第三类。除了这种例外情况以外,本文下面几节都是按照上面的顺序来讨论 Eclipse 重构工具的。
显然,您即便没有特别的工具,也可以在文件系统中重命名文件或者是移动文件,但是如果操作对象是 Java 源代码文件,您就需要编辑很多文件,更新其中的 import
或 package
语句。与此类似,用某种文本编辑器的搜索与替换功能也可以很容易地给类、方法和变量重新命名,但是这样做的时候必须十分小心,因为不同的类可能具有名称相似的方法或者变量;要是从头到尾检查项目中所有的文件,来保证每个东西的标识和修改的正确性,那可真够乏味的。
Eclipse 的 Rename 和 Move 工具能够十分聪明地在整个项目中完成这样的修改,而不需要用户的干涉。这是因为 Eclipse 可以理解代码的语义,从而能够识别出对某个特定方法、变量或者类名称的引用。简化这一任务有助于确保方法、变量和类的名称能够清晰地指示其用途。
我们经常可以发现代码的名字不恰当或者令人容易误解,这是因为代码与最初设计的功能有所不同。比方说,某个用来在文件中查找特定单词的程序也许会扩展为在 Web 页面中通过 URL 获取 InputStream
的操作。如果这一输入流最初叫做 file
,那么就应该修改它的名字,以便能反映其新增的更加一般的特性,比方说 sourceStream
。开发人员经常无法成功地修改这些名称,因为这个过程是十分混乱和乏味的。这当然也会把下一个不得不对这些类进行操作的开发人员弄糊涂。
要对某个 Java 元素进行重命名,只需要简单地从 Package Explorer 视图中点击这个元素,或者从Java 源代码文件中选中这个元素,然后选择菜单项 Refactor > Rename。在对话框中输入新的名称,然后选择是否需要 Eclipse 也改变对这个名称的引用。实际显示出来的确切内容与您所选元素的类型有关。比方说,如果选择的属性具有 getter 和 setter 方法,那么也就可以同时更新这些方法的名称,以反映新的属性。图1显示了一个简单的例子。
就像所有的 Eclipse 重构操作一样,当您指定了全部用来执行重构的必要信息之后,您就可以点击 Preview 按钮,然后在一个对话框中对比 Eclipse 打算进行哪些变更,您可以分别否决或者确认每一个受到影响的文件中的每一项变更。如果您对于 Eclipse 正确执行变更的能力有信心的话,您可以只按下 OK按钮。显然,如果您不确定重构到底做了什么事情,您就会想先预览一下,但是对于 Rename 和 Move 这样简单的重构而言,通常没有必要预览。
Move 操作与 Rename 十分相似:您选择某个 Java 元素(通常是一个类),为其指定一个新位置,并定义是否需要更新引用。然后,您可以选择 Preview检查变更情况,或者选择 OK 立即执行重构,如图2所示。
在某些平台上(特别是 Windows),您还可以在 Package Explorer 视图中通过简单拖放的方法将类从一个包或者文件夹中移到另一个包或文件夹中。所有的引用都会自动更新。
Eclipse 中有大量的重构工具,使您能够自动改变类的关系。这些重构工具并没有 Eclipse 提供的其他工具那么常用,但是很有价值,因为它们能够执行非常复杂的任务。可以说,当它们用得上的时候,就会非常有用。
Convert Anonymous Class(转换匿名类)和 Convert Nested Type(转换嵌套类)这两种重构方法比较相似,它们都将某个类从其当前范围移动到包含这个类的范围上。
匿名类是一种语法速写标记,使您能够在需要实现某个抽象类或者接口的地方创建一个类的实例,而不需要显式提供类的名称。比如在创建用户界面中的监听器时,就经常用到匿名类。在清单1中,假设 Bag 是在其他地方定义的一个接口,其中声明了两个方法, get()
和 set()
。
清单 1. Bag 类
public class BagExample { void processMessage(String msg) { Bag bag = new Bag() { Object o; public Object get() { return o; } public void set(Object o) { this.o = o; } }; bag.set(msg); MessagePipe pipe = new MessagePipe(); pipe.send(bag); } }
当匿名类变得很大,其中的代码难以阅读的时候,您就应该考虑将这个匿名类变成严格意义上的类;为了保持封装性(换句话说,就是将它隐藏起来,使得不必知道它的外部类不知道它),您应该将其变成嵌套类,而不是顶级类。您可以在这个匿名类的内部点击,然后选择 Refactor > Convert Anonymous Class to Nested 就可以了。当出现确认对话框的时候,为这个类输入名称,比如 BagImpl
,然后选择 Preview或者 OK。这样,代码就变成了如清单2所示的情形。
清单 2. 经过重构的 Bag 类
public class BagExample { private final class BagImpl implements Bag { Object o; public Object get() { return o; } public void set(Object o) { this.o = o; } } void processMessage(String msg) { Bag bag = new BagImpl(); bag.set(msg); MessagePipe pipe = new MessagePipe(); pipe.send(bag); } } |
当您想让其他的类使用某个嵌套类时,Convert Nested Type to Top Level 就很有用了。比方说,您可以在一个类中使用值对象,就像上面的 BagImpl
类那样。如果您后来又决定应该在多个类之间共享这个数据,那么重构操作就能从这个嵌套类中创建新的类文件。您可以在源代码文件中高亮选中类名称(或者在 Outline 视图中点击类的名称),然后选择 Refactor > Convert Nested Type to Top Level,这样就实现了重构。
这种重构要求您为装入实例提供一个名字。重构工具也会提供建议的名称,比如 example
,您可以接受这个名字。这个名字的意思过一会儿就清楚了。点击 OK 之后,外层类 BagExample
就会变成清单3所示的样子。
public class BagExample { void processMessage(String msg) { Bag bag = new BagImpl(this); bag.set(msg); MessagePipe pipe = new MessagePipe(); pipe.send(bag); } } |
请注意,当一个类是嵌套类的时候,它可以访问其外层类的成员。为了保留这种功能,重构过程将一个装入类 BagExample 的实例放在前面那个嵌套类中。这就是之前要求您输入名称的实例变量。同时也创建了用于设置这个实例变量的构造函数。重构过程创建的新类 BagImpl 如清单4所示。
final class BagImpl implements Bag { private final BagExample example; /** * @paramBagExample */ BagImpl(BagExample example) { this.example = example; // TODO Auto-generated constructor stub } Object o; public Object get() { return o; } public void set(Object o) { this.o = o; } } |
如果您的情况与这个例子相同,不需要保留对 BagExample
的访问,您也可以很安全地删除这个实例变量与构造函数,将 BagExample
类中的代码改成缺省的无参数构造函数。
还有两个重构工具,Push Down 和 Pull Up,分别实现将类方法或者属性从一个类移动到其子类或父类中。假设您有一个名为 Vehicle
的抽象类,其定义如清单5所示。
public abstract class Vehicle { protected int passengers; protected String motor; public int getPassengers() { return passengers; } public void setPassengers(int i) { passengers = i; } public String getMotor() { return motor; } public void setMotor(String string) { motor = string; } } |
您还有一个 Vehicle
的子类,类名为 Automobile
,如清单6所示。
public class Automobile extends Vehicle { private String make; private String model; public String getMake() { return make; } public String getModel() { return model; } public void setMake(String string) { make = string; } public void setModel(String string) { model = string; } } |
请注意, Vehicle
有一个属性是 motor
。如果您知道您将永远只处理汽车,那么这样做就好了;但是如果您也允许出现划艇之类的东西,那么您就需要将 motor
属性从 Vehicle
类下放到 Automobile
类中。为此,您可以在 Outline 视图中选择 motor
,然后选择 Refactor > Push Down。
Eclipse 还是挺聪明的,它知道您不可能总是单单移动某个属性本身,因此还提供了 Add Required 按钮,不过在 Eclipse 2.1 中,这个功能并不总是能正确地工作。您需要验证一下,看所有依赖于这个属性的方法是否都推到了下一层。在本例中,这样的方法有两个,即与 motor
相伴的 getter 和 setter 方法,如图3所示。
图 3. 加入所需的成员
在按过 OK按钮之后, motor
属性以及 getMotor()
和 setMotor()
方法就会移动到 Automobile
类中。清单7显示了在进行了这次重构之后 Automobile
类的情形。
public class Automobile extends Vehicle { private String make; private String model; protected String motor; public String getMake() { return make; } public String getModel() { return model; } public void setMake(String string) { make = string; } public void setModel(String string) { model = string; } public String getMotor() { return motor; } public void setMotor(String string) { motor = string; } } |
Pull Up 重构与 Push Down 几乎相同,当然 Pull Up 是将类成员从一个类中移到其父类中,而不是子类中。如果您稍后改变主意,决定还是把 motor
移回到 Vehicle
类中,那么您也许就会用到这种重构。同样需要提醒您,一定要确认您是否选择了所有必需的成员。
Automobile
类中具有成员 motor,这意味着您如果创建另一个子类,比方说 Bus
,您就还需要将 motor
(及其相关方法)加入到 Bus
类中。有一种方法可以表示这种关系,即创建一个名为 Motorized
的接口, Automobile
和 Bus
都实现这个接口,但是 RowBoat
不实现。
创建 Motorized
接口最简单的方法是在 Automobile
上使用 Extract Interface 重构。为此,您可以在 Outline 视图中选择 Automobile
,然后从菜单中选择 Refactor > Extract Interface。您可以在弹出的对话框中选择您希望在接口中包含哪些方法,如图4所示。
点击 OK 之后,接口就创建好了,如清单8所示。
public interface Motorized { public abstract String getMotor(); public abstract void setMotor(String string); } |
同时, Automobile
的类声明也变成了下面的样子:
public class Automobile extends Vehicle implements Motorized |
本重构工具类型中最后一个是 User Supertyp Where Possible。想象一个用来管理汽车细帐的应用程序。它自始至终都使用 Automobile
类型的对象。如果您想处理所有类型的交通工具,那么您就可以用这种重构将所有对 Automobile
的引用都变成对 Vehicle 的引用(参看图5)。如果您在代码中用 instanceof
操作执行了任何类型检查的话,您将需要决定在这些地方适用的是原先的类还是父类,然后选中第一个选项“Use the selected supertype in 'instanceof' expressions”。
图 5. 将 Automobile 改成其父类 Vehicle
使用父类的需求在 Java 语言中经常出现,特别是在使用了 Factory Method 模式的情况下。这种模式的典型实现方式是创建一个抽象类,其中具有静态方法 create()
,这个方法返回的是实现了这个抽象类的一个具体对象。如果需创建的具体对象的类型依赖于实现的细节,而调用类对实现细节并不感兴趣的情况下,可以使用这一模式。
最大一类重构是实现了类内部代码重组的重构方法。在所有的重构方法中,只有这类方法允许您引入或者移除中间变量,根据原有方法中的部分代码创建新方法,以及为属性创建 getter 和 setter 方法。
有一些重构方法是以 Extract 这个词开头的:Extract Method、Extract Local Variable 以及Extract Constants。第一个 Extract Method 的意思您可能已经猜到了,它根据您选中的代码创建新的方法。我们以清单8中那个类的 main()
方法为例。它首先取得命令行选项的值,如果有以 -D 开头的选项,就将其以名-值对的形式存储在一个 Properties
对象中。
import java.util.Properties; import java.util.StringTokenizer; public class StartApp { public static void main(String[] args) { Properties props = new Properties(); for (int i= 0; i < args.length; i++) { if(args[i].startsWith("-D")) { String s = args[i].substring(2); StringTokenizer st = new StringTokenizer(s, "="); if(st.countTokens() == 2) { props.setProperty(st.nextToken(), st.nextToken()); } } } //continue... } } |
将一部分代码从一个方法中取出并放进另一个方法中的原因主要有两种。第一种原因是这个方法太长,并且完成了两个以上逻辑上截然不同的操作。(我们不知道上面那个 main()
方法还要处理哪些东西,但是从现在掌握的证据来看,这不是从其中提取出一个方法的理由。)另一种原因是有一段逻辑上清晰的代码,这段代码可以被其他方法重用。比方说在某些时候,您发现自己在很多不同的方法中都重复编写了相同的几行代码。那就有可能是需要重构的原因了,不过除非真的需要重用这部分代码,否则您很可能并不会执行重构。
假设您还需要在另外一个地方解析名-值对,并将其放在 Properties
对象中,那么您可以将包含 StringTokenizer
声明和下面的 if
语句的这段代码抽取出来。为此,您可以高亮选中这段代码,然后从菜单中选择 Refactor > Extract Method。您需要输入方法名称,这里输入 addProperty
,然后验证这个方法的两个参数, Properties prop
和 Strings
。清单9显示由 Eclipse 提取了 addProp()
方法之后类的情况。
import java.util.Properties; import java.util.StringTokenizer; public class Extract { public static void main(String[] args) { Properties props = new Properties(); for (int i = 0; i < args.length; i++) { if (args[i].startsWith("-D")) { String s = args[i].substring(2); addProp(props, s); } } } private static void addProp(Properties props, String s) { StringTokenizer st = new StringTokenizer(s, "="); if (st.countTokens() == 2) { props.setProperty(st.nextToken(), st.nextToken()); } } } |
Extract Local Variable 重构取出一段被直接使用的表达式,然后将这个表达式首先赋值给一个局部变量。然后在原先使用那个表达式的地方使用这个变量。比方说,在上面的方法中,您可以高亮选中对 st.nextToken()
的第一次调用,然后选择 Refactor > Extract Local Variable。您将被提示输入一个变量名称,这里输入 key
。请注意,这里有一个将被选中表达式所有出现的地方都替换成新变量的引用的选项。这个选项通常是适用的,但是对这里的 nextToken()
方法不适用,因为这个方法(显然)在每一次调用的时候都返回不同的值。确认这个选项未被选中。参见图6。
接下来,在第二次调用 st.nextToken()
的地方重复进行重构,这一次调用的是一个新的局部变量 value
。清单10显示了这两次重构之后代码的情形。
private static void addProp(Properties props, String s) { StringTokenizer st = new StringTokenizer(s, "="); if(st.countTokens() == 2) { String key = st.nextToken(); String value = st.nextToken(); props.setProperty(key, value); } } |
用这种方式引入变量有几点好处。首先,通过为表达式提供有意义的名称,可以使得代码执行的任务更加清晰。第二,代码调试变得更容易,因为我们可以很容易地检查表达式返回的值。最后,在可以用一个变量替换同一表达式的多个实例的情况下,效率将大大提高。
Extract Constant 与 Extract Local Variable 相似,但是您必须选择静态常量表达式,重构工具将会把它转换成静态的 final 常量。这在将硬编码的数字和字符串从代码中去除的时候非常有用。比方说,在上面的代码中我们用“-D”这一命令行选项来定义名-值对。先将“-D”高亮选中,选择 Refactor > Extract Constant,然后输入 DEFINE 作为常量的名称。重构之后的代码如清单11所示:
public class Extract { private static final String DEFINE = "-D"; public static void main(String[] args) { Properties props = new Properties(); for (int i = 0; i < args.length; i++) { if (args[i].startsWith(DEFINE)) { String s = args[i].substring(2); addProp(props, s); } } } // ... |
对于每一种 Extract... 类的重构,都存在对应的 Inline... 重构,执行与之相反的操作。比方说,如果您高亮选中上面代码中的变量 s,选择 Refactor > Inline...,然后点击 OK,Eclipse 就会在调用 addProp()
的时候直接使用 args[i].substring(2)
这个表达式,如下所示:
if(args[i].startsWith(DEFINE)) { addProp(props,args[i].substring(2)); } |
这样比使用临时变量效率更高,代码也变得更加简要,至于这样的代码是易读还是含混,就取决于您的观点了。不过一般说来,这样的内嵌重构没什么值得推荐的地方。
您可以按照用内嵌表达式替换变量的相同方法,高亮选中方法名,或者静态 final 常量,然后从菜单中选择 Refactor > Inline...,Eclipse 就会用方法的代码替换方法调用,或者用常量的值替换对常量的引用。
通常我们认为将对象的内部结构暴露出来是一种不好的做法。这也正是 Vehicle
类及其子类都具有 private 或者 protected 属性,而用 public setter 和 getter 方法来访问属性的原因。这些方法可以用两种不同的方式自动生成。
第一种生成这些方法的方式是使用 Source > Generate Getter and Setter 菜单。这将会显示一个对话框,其中包含所有尚未存在的 getter 和 setter 方法。不过因为这种方式没有用新方法更新对这些属性的引用,所以并不算是重构;必要的时候,您必须自己完成更新引用的工作。这种方式可以节约很多时间,但是最好是在一开始创建类的时候,或者是向类中加入新属性的时候使用,因为这些时候还不存在对属性的引用,所以不需要再修改其他代码。
第二种生成 getter 和 setter 方法的方式是选中某个属性,然后从菜单中选择 Refactor > Encapsulate Field。这种方式一次只能为一个属性生成 getter 和 setter 方法,不过它与 Source > Generate Getter and Setter 相反,可以将对这个属性的引用改变成对新方法的调用。
例如,我们可以先创建一个新的简版 Automobile
类,如清单12所示。
public class Automobile extends Vehicle { public String make; public String model; } |
接下来,创建一个类实例化了 Automobile
的类,并直接访问 make
属性,如清单13所示。
public class AutomobileTest { public void race() { Automobilecar1 = new Automobile(); car1.make= "Austin Healy"; car1.model= "Sprite"; // ... } } |
现在封装 make
属性。先高亮选中属性名称,然后选择 Refactor > Encapsulate Field。在弹出的对话框中输入 getter 和 setter 方法的名称——如您所料,缺省的方法名称分别是 getMake() 和 setMake()。您也可以选择与这个属性处在同一个类中的方法是继续直接访问该属性,还是像其他类那样改用这些访问方法。(有一些人非常倾向于使用这两种方式的某一种,不过碰巧在这种情况下您选择哪一种方式都没有区别,因为 Automobile
中没有对 make
属性的引用。)
点击 OK之后, Automobile 类中的 make
属性就变成了私有属性,也同时具有了 getMake()
和 setMake()
方法。
>
public class Automobile extends Vehicle { private String make; public String model; public void setMake(String make) { this.make = make; } public String getMake() { return make; } } |
AutomobileTest
类也要进行更新,以便使用新的访问方法,如清单15所示。
public class AutomobileTest { public void race() { Automobilecar1 = new Automobile(); car1.setMake("Austin Healy"); car1.model= "Sprite"; // ... } } |
本文介绍的最后一个重构方法也是最难以使用的方法:Change Method Signature(改变方法的签名)。这种方法的功能显而易见——改变方法的参数、可见性以及返回值的类型。而进行这样的改变对于调用这个方法的其他方法或者代码会产生什么影响,就不是那么显而易见了。这么也没有什么魔方。如果代码的改变在被重构的方法内部引发了问题——变量未定义,或者类型不匹配——重构操作将对这些问题进行标记。您可以选择是接受重构,稍后改正这些问题,还是取消重构。如果这种重构在其他的方法中引发问题,就直接忽略这些问题,您必须在重构之后亲自修改。
为澄清这一点,考虑清单16中列出的类和方法。
public class MethodSigExample { public int test(String s, int i) { int x = i + s.length(); return x; } } |
上面这个类中的 test()
方法被另一个类中的方法调用,如清单17所示。
public void callTest() { MethodSigExample eg = new MethodSigExample(); int r = eg.test("hello", 10); } |
在第一个类中高亮选中 test
,然后选择 Refactor > Change Method Signature。您将看到如图8所示的对话框。
第一个选项是改变该方法的可见性。在本例中,将其改变为 protected 或者 private,这样第二个类的 callTest()
方法就不能访问这个方法了。(如果这两个类在不同的包中,将访问方法设为缺省值也会引起这样的问题。) Eclipse 在进行重构的时候不会将这些问题标出,您只有自己选择适当的值。
下面一个选项是改变返回值类型。如果将返回值改为 float
,这不会被标记成错误,因为 test()
方法返回语句中的 int
会自动转换成 float
。即便如此,在第二个类的 callTest()
方法中也会引起问题,因为 float
不能转换成 int
。您需要将 test()
的返回值改为 int
,或者是将 callTest()
中的 r
改为 float
。
如果将第一个参数的类型从 String
变成 int
,那么也得考虑相同的问题。在重构的过程中这些问题将会被标出,因为它们会在被重构的方法内部引起问题: int
不具有方法 length()
。然而如果将其变成 StringBuffer
,问题就不会标记出来,因为 StringBuffer
的确具有方法 length()
。当然这会在 callTest()
方法中引起问题,因为它在调用 test()
的时候还是把一个 String
传递进去了。
前面提到过,在重构引发了问题的情况下,不管问题是否被标出,您都可以一个一个地修正这些问题,以继续下去。还有一种方法,就是先行修改这些错误。如果您打算删除不再需要的参数 i
,那么可以先从要进行重构的方法中删除对它的引用。这样删除参数的过程就更加顺利了。
最后一件需要解释的事情是 Default Value 选项。这一选项值仅适用于将参数加入方法签名中的情况。比方说,如果我们加入了一个类型为 String
的参数,参数名为 n
,其缺省值为 world
,那么在 callTest()
方法中调用 test()
的代码就变成下面的样子:
public void callTest() { MethodSigExample eg = new MethodSigExample(); int r = eg.test("hello", 10, "world"); } |
在这场有关 Change Method Signature 重构的看似可怕的讨论中,我们并没有隐藏其中的问题,但却一直没有提到,这种重构其实是非常强大的工具,它可以节约很多时间,通常您必须进行仔细的计划才能成功地使用它。
更多您可以参阅在 developerWorks 全球站点上的 关于重构的文章.
评论
[*]
[url][/url][img][/img]
引用 [img][/img][url][/url]
引用 |
相关推荐
"512572.htm"可能是一篇关于Eclipse重构的详细教程或文章,可能涵盖了如何使用Eclipse的重构功能,例如如何执行“提取方法”来减少代码重复,如何“重命名”变量或类以保持一致性,以及如何“移动”代码片段到更合适...
我们将通过一个具体的程序实例来展示Eclipse重构的几个关键步骤。 首先,Eclipse的重命名功能可以方便地更新所有相关引用,无论是方法、字段还是变量。在本例中,我们使用《Refactoring:Improving the Design of ...
### 在Eclipse中实施重构 #### 重构介绍 重构是一种重要的软件工程实践,指的是在不改变软件外部行为的前提下,对代码进行改进的过程。这一过程旨在优化代码结构,提高代码的可读性和可维护性,同时减少未来的修改...
重构到ec 该项目包含将Java流重构为惯用的Eclipse集合的示例。重构集合:使Java Streams更精简,更干净描述寻找优化Java应用程序的方法? 是否希望看到切实的内存节省以及更清晰,更易读的代码? 是否希望为函数式...
9.3 使用Eclipse重构功能 Eclipse的重构功能可以帮助开发者对代码进行结构上的修改,而不影响其功能。例如,它可以重命名变量、函数,提取方法,移动代码片段等,同时更新所有相关的引用,使得代码维护更加便捷。 ...
* 重构功能:使用Eclipse重构功能,可以在不影响程序行为的情况下进行系统范围内的代码更改。 * 抽取方法:将程序中多次出现的代码段抽取出来形成方法,可以减少代码的长度并增加程序的可读性和易维护性,同时使方法...
【Eclipse重构】 重构是不改变代码外在行为的情况下,改善代码结构的过程。Eclipse的重构功能包括重命名变量、抽取方法和抽取常量,提高代码可读性和维护性。 【Eclipse搜索】 Eclipse搜索功能分为基本的查找/替换...
在本文中,我们将深入探讨如何在Eclipse集成开发环境中利用自动重构功能来优化Java代码。Eclipse的自动重构工具为开发者提供了强大的支持,包括但不限于重命名、移动方法、内联、抽取方法和更改方法特征符等功能。...
Eclipse是一个开放源代码的、可扩展的集成开发环境(IDE)。最初由IBM公司开发,后来由Eclipse基金会管理。Eclipse主要用于Java语言的开发,但通过安装各种插件,它可以扩展支持其他编程语言和平台,例如C/C++、...
Eclipse重构快捷键是指在代码重构时使用的shortcut键,它可以帮助用户快速完成代码重构任务。常用的Eclipse重构快捷键包括: 1. Alt+Shift+Z:撤销重构。 2. Alt+Shift+M:抽取方法。 3. Alt+Shift+L:抽取局部变量...
在Eclipse中进行重构是提升代码质量和可维护性的重要手段,它涉及到一系列的代码修改操作,但不改变程序的功能。Eclipse提供了丰富的重构工具,帮助开发者高效地进行代码优化。以下是一些主要的重构知识点: 1. **...
在IT行业中,Eclipse是一款广泛使用的开源集成开发环境(IDE),尤其在Java开发领域享有盛誉。然而,Eclipse的功能并不仅限于Java,它也支持多种其他编程语言,包括JavaScript(JS)。针对JS开发,Eclipse提供了丰富...
- **重构**:Eclipse提供了丰富的重构工具,如重命名、提取方法、移动文件等。 - **构建工具**:Maven和Gradle插件使得Eclipse能很好地管理依赖和构建流程。 - **调试**:Eclipse的调试器支持断点、单步执行、...
8. **代码重构**:提供代码重构工具,帮助开发者安全地修改代码结构,而不影响应用的运行。 在压缩包中,`content.jar`和`artifacts.jar`通常包含了插件的运行时内容和元数据信息。`features`目录下的文件描述了...
此外,Eclipse还支持代码重构,如重命名变量、提取方法等,这些都能帮助开发者保持代码的整洁和可维护性。 在调试方面,Eclipse提供了强大的调试工具。通过设置断点、单步执行、查看变量值、调用栈分析等手段,可以...
同时,Eclipse的重构工具如提取方法、重命名变量等,能让你的代码更加整洁和易于维护。 6. 使用插件:Eclipse的一大优势在于其丰富的插件库,例如Mylyn用于任务管理,Subversive或Git插件用于版本控制,JUnit进行...