副标题#e#
为什么重构?
重构是指在不改变措施成果的前提下改变其布局。重构是一项成果强大的技能,可是执行起来需要倍加小心才行。主要的危险在于大概在不经意中引入一些错误,尤其是在举办手工重构的时候更是如此。这种危险激发了对重构技能的普遍品评:今世码不会瓦解的时候为什么要修改它呢?
您需要举办代码重构的原因大概有以下几个:传说中的第一个原因是:需要担任为某个陈腐产物而开拓的年月长远的代码,可能溘然遇到这些代码。最初的开拓团队已经不在了。我们必需建设增加了新特性的新版本软件,可是这些代码已经无法领略了。新的开拓步队夜以继日地事情,破译代码然后映射代码,颠末大量的筹划与设计之后,人们将这些代码支解成碎片。历经重重患难之后,所有这些对象都凭据新版本的要求归位了。这是英雄般的重构故事,险些没有人能在经验了这些之后在世报告这样的故事。
尚有一种现实一些的环境是项目中插手了新的需求,需要对设计举办修改。至于是因为在最初的筹划进程中失察,照旧由于回收了迭代式的开拓进程(好比火速开拓,可能是测试驱动的开拓)而在开拓进程中有意引入需求,这两者并没有实质性的区别。这样的重构的局限要小得多,其内容一般涉及通过引入接口可能抽象类来变动类的担任干系,以及对类举办支解和从头组织,等等。
重构的最后一个原因是,当存在可用的自动重构东西时,可以有一个用来预先生成代码的快捷方法——就比如在您无法确定如何拼写某个单词的时候,可以用某种拼写查抄东西输入这个单词。好比说,您可以用这种平淡无奇的重构要领生成 getter 和 setter 要领,一旦熟悉了这样的东西,它就可觉得您节减许多的时间。
Eclipse 的重构东西无意举办英雄级的重构——适合这种局限的东西险些没有——可是岂论是否用到火速开拓技能,Eclipse 的东西对付一般措施员修改代码的事情都具有无法权衡的代价。究竟任何巨大的操纵只要可以或许自动举办,就可以不那么愁闷了。只要您知道Eclipse实现了什么样的重构东西,并领略了它们的合用环境,您的出产力就会获得极大的提高。
要低落对代码造成粉碎的风险,有两种重要的要领。第一种要领是对代码举办一套完全彻底的单位测试:在重构之前和之后都必需通过这样的测试。第二种要领是利用自动化的东西来举办重构,好比说Eclipse的重构特性。
将彻底的测试与自动化重构团结起来就会越发有效了,这样重构也就从一种神秘的艺术酿成了有用的日常东西。为了增加新的成果可能改造代码的可维护性,我们可以在不影响原有代码成果的基本上迅速且安详地改变其布局。这种本领会对您设计和开拓代码的方法发生极大的影响,即即是您没有将其团结到正式的火速要领中也没有干系。
Eclipse 中重构的范例
Eclipse 的重构东西可以分为三大类(下面的顺序也就是这些东西在 Refactoring 菜单中呈现的顺序):
对代码举办重定名以及改变代码的物理布局,包罗对属性、变量、类以及接口从头定名,尚有移动包和类等。
改变类一级的代码逻辑布局,包罗将匿名类转变为嵌套类,将嵌套类转变为顶级类、按照详细的类建设接口,以及从一个类中将要领可能属性移到子类可能父类中。
改变一个类内部的代码,包罗将局部变量酿成类的属性、将某个要领中选中部门的代码酿成一个独立的要领、以及为属性生成 getter 和 setter 要领。
尚有几个重构东西并不能完全归入这三个种类,出格是 Change Method Signature,不外在本文中照旧将这个东西归入第三类。除了这种破例环境以外,本文下面几节都是凭据上面的顺序来接头Eclipse重构东西的。
物理重组与重定名
显然,您即便没有出格的东西,也可以在文件系统中重定名文件可能是移动文件,可是假如操纵工具是 Java 源代码文件,您就需要编辑许多文件,更新个中的 import 或 package 语句。与此雷同,用某种文本编辑器的搜索与替换成果也可以很容易地给类、要领和变量从头定名,可是这样做的时候必需十分小心,因为差异的类大概具有名称相似的要领可能变量;要是从新到尾查抄项目中所有的文件,来担保每个对象的标识和修改的正确性,那可真够乏味的。
Eclipse 的 Rename 和 Move 东西可以或许十分智慧地在整个项目中完成这样的修改,而不需要用户的过问干与。这是因为Eclipse可以领略代码的语义,从而可以或许识别出对某个特定要领、变量可能类名称的引用。简化这一任务有助于确保要领、变量和类的名称可以或许清晰地指示其用途。
#p#分页标题#e#
我们常常可以发明代码的名字不得当可能令人容易误解,这是因为代码与最初设计的成果有所差异。例如说,某个用来在文件中查找特定单词的措施也许会扩展为在 Web 页面中通过 URL 获取 InputStream 的操纵。假如这一输入流最初叫做 file ,那么就应该修改它的名字,以便能反应其新增的越发一般的特性,例如说 sourceStream 。开拓人员常常无法乐成地修改这些名称,因为这个进程是十分杂乱和乏味的。这虽然也会把下一个不得差池这些类举办操纵的开拓人员弄糊涂。
要对某个 Java 元素举办重定名,只需要简朴地从 Package Explorer 视图中点击这个元素,可能从Java 源代码文件中选中这个元素,然后选择菜单项 Refactor > Rename。在对话框中输入新的名称,然后选择是否需要Eclipse也改变对这个名称的引用。实际显示出来简直切内容与您所选元素的范例有关。例如说,假如选择的属性具有 getter 和 setter 要领,那么也就可以同时更新这些要领的名称,以反应新的属性。图1显示了一个简朴的例子。
图 1. 重定名一个局部变量
#p#副标题#e#
就像所有的Eclipse重构操纵一样,当您指定了全部用来执行重构的须要信息之后,您就可以点击 Preview 按钮,然后在一个对话框中比拟Eclipse规划举办哪些改观,您可以别离反对可能确认每一个受到影响的文件中的每一项改观。假如您对付Eclipse正确执行改观的本领有信心的话,您可以只按下 OK按钮。显然,假如您不确定重构到底做了什么工作,您就会想先预览一下,可是对付 Rename 和 Move 这样简朴的重构而言,凡是没有须要预览。
Move 操纵与 Rename 十分相似:您选择某个 Java 元素(凡是是一个类),为其指定一个新位置,并界说是否需要更新引用。然后,您可以选择 Preview查抄改观环境,可能选择 OK 当即执行重构,如图2所示。
图 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);
}
}
#p#分页标题#e#
当您想让其他的类利用某个嵌套类时,Convert Nested Type to Top Level 就很有用了。例如说,您可以在一个类中利用值工具,就像上面的 BagImpl 类那样。假如您厥后又抉择应该在多个类之间共享这个数据,那么重构操纵就能从这个嵌套类中建设新的类文件。您可以在源代码文件中高亮选中类名称(可能在 Outline 视图中点击类的名称),然后选择 Refactor > Convert Nested Type to Top Level,这样就实现了重构。
这种重构要求您为装入实例提供一个名字。重构东西也会提供发起的名称,好比 example ,您可以接管这个名字。这个名字的意思过一会儿就清楚了。点击 OK 之后,外层类 BagExample 就会酿成清单3所示的样子。
清单 3. 颠末重构的 Bag 类
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所示。
清单 4. BagImpl 类
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所示。
清单 5. 抽象的 Vehicle 类
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所示。
清单6. Automobile 类
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 按钮,不外在Eclipse2.1 中,这个成果并不老是能正确地事情。您需要验证一下,看所有依赖于这个属性的要领是否都推到了下一层。在本例中,这样的要领有两个,即与 motor 相伴的 getter 和 setter 要领,如图3所示。
图 3. 插手所需的成员
在按过 OK按钮之后, motor 属性以及 getMotor() 和 setMotor() 要领就会移动到 Automobile 类中。清单7显示了在举办了这次重构之后 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;
}
}
#p#分页标题#e#
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所示。
图 4. 提取 Motorized 接口
点击 OK 之后,接口就建设好了,如清单8所示。
清单 8. Motorized 接口
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 工具中。
清单 8. main()
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() 要领还要处理惩罚哪些对象,可是以后刻把握的证据来看,这不是从个中提取出一个要领的来由。)另一种原因是有一段逻辑上清晰的代码,这段代码可以被其他要领重用。例如说在某些时候,您发明本身在许多差异的要领中都反复编写了沟通的几行代码。那就有大概是需要重构的原因了,不外除非真的需要重用这部门代码,不然您很大概并不会执行重构。
#p#分页标题#e#
假设您还需要在别的一个处所理会名-值对,并将其放在 Properties 工具中,那么您可以将包括 StringTokenizer 声明和下面的 if 语句的这段代码抽取出来。为此,您可以高亮选中这段代码,然后从菜单中选择 Refactor > Extract Method。您需要输入要领名称,这里输入 addProperty ,然后验证这个要领的两个参数, Properties prop 和 Strings 。清单9显示由Eclipse提取了 addProp() 要领之后类的环境。
清单 9. 提取出来的 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。
图 6. 不全部替换所选的表达式
接下来,在第二次挪用 st.nextToken() 的处所反复举办重构,这一次挪用的是一个新的局部变量 value 。清单10显示了这两次重构之儿女码的景象。
清单 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所示:
清单 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 要领来会见属性的原因。这些要领可以用两种差异的方法自动生成。
#p#分页标题#e#
第一种生成这些要领的方法是利用 Source > Generate Getter and Setter 菜单。这将会显示一个对话框,个中包括所有尚未存在的 getter 和 setter 要领。不外因为这种方法没有用新要领更新对这些属性的引用,所以并不算是重构;须要的时候,您必需本身完成更新引用的事情。这种方法可以节省许多时间,可是最好是在一开始建设类的时候,可能是向类中插手新属性的时候利用,因为这些时候还不存在对属性的引用,所以不需要再修改其他代码。
第二种生成 getter 和 setter 要领的方法是选中某个属性,然后从菜单中选择 Refactor > Encapsulate Field。这种方法一次只能为一个属性生成 getter 和 setter 要领,不外它与 Source > Generate Getter and Setter 相反,可以将对这个属性的引用改酿成对新要领的挪用。
譬喻,我们可以先建设一个新的简版 Automobile 类,如清单12所示。
清单 12. 简朴的 Automobile 类
public class Automobile extends Vehicle
{
public String make;
public String model;
}
接下来,建设一个类实例化了 Automobile 的类,并直接会见 make 属性,如清单13所示。
清单 13. 实例化 Automobile
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 属性的引用。)
图7. 封装属性
点击 OK之后, Automobile 类中的 make 属性就酿成了私有属性,也同时具有了 getMake() 和 setMake() 要领。
>
清单 14. 颠末重构的 Automobile 类
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所示。
>清单 15. AutomobileTest 类
public class AutomobileTest
{
public void race()
{
Automobilecar1 = new Automobile();
car1.setMake("Austin Healy");
car1.model= "Sprite";
// ...
}
}
改变要领的签名
本文先容的最后一个重构要领也是最难以利用的要领:Change Method Signature(改变要领的签名)。这种要领的成果显而易见——改变要领的参数、可见性以及返回值的范例。而举办这样的改变对付挪用这个要领的其他要领可能代码会发生什么影响,就不是那么显而易见了。这么也没有什么魔方。假如代码的改变在被重构的要领内部激发了问题——变量未界说,可能范例不匹配——重构操纵将对这些问题举办标志。您可以选择是接管重构,稍后纠正这些问题,照旧打消重构。假如这种重构在其他的要领中激发问题,就直接忽略这些问题,您必需在重构之后亲自修改。
为澄清这一点,思量清单16中列出的类和要领。
清单 16. MethodSigExample 类
public class MethodSigExample
{
public int test(String s, int i)
{
int x = i + s.length();
return x;
}
}
上面这个类中的 test() 要领被另一个类中的要领挪用,如清单17所示。
清单 17. callTest 要领
public void callTest()
{
MethodSigExample eg = new MethodSigExample();
int r = eg.test("hello", 10);
}
在第一个类中高亮选中 test ,然后选择 Refactor > Change Method Signature。您将看到如图8所示的对话框。
图 8. Change Method Signature 选项
#p#分页标题#e#
第一个选项是改变该要领的可见性。在本例中,将其改变为 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 重构的看似可骇的接头中,我们并没有埋没个中的问题,但却一直没有提到,这种重构其实长短常强大的东西,它可以节省许多时间,凡是您必需举办仔细的打算才气乐成地利用它。
竣事语
Eclipse 提供的东西使重构变得简朴,熟悉这些东西将有助于您提高效率。火速开拓要领回收迭代方法增加措施特性,因此需要依赖于重构技能来改变和扩展措施的设计。但即便您并没有利用要求举办正式重构的要领,Eclipse 的重构东西照旧可以在举办一般的代码修改时提供节省时间的要领。假如您花些时间熟悉这些东西,那么当呈现可以操作它们的环境时,您就能意识到所耗费的时间是值得的。