重构改善既有代码的设计--简化函数调用

前言:关于缩减参数列的重构手法,DougLea对我提出了一个警告:并发编程往往需要使用较长的参数列,因为这样你可以保证传递给函数的参数都是不可被修改的,例如内置型对象和值对象一定是不可变的。通常,你可以使用不可变对象取代这样的长参数列,但另一方面你也必须对此类重构保持谨慎。

多年来,我一直坚守一个很有价值的习惯:明确地将“修改对象状态”的函数(修改函数)和“查询对象状态”的函数(查询函数)分开设计。

1、RenameMethod(函数改名)

动机:函数的名称未能揭示函数的用途。

2、AddParameter(添加参数)

动机:某个函数需要从调用端得到更多信息。

3、RemoveParameter(移除参数)

动机:函数本体不再需要某个参数

4、SeparateQueryfromModifier(将查询函数和修改函数分离)

动机:某个函数既返回对象状态值,有修改对象状态。

做法:建立两个不同的函数,其中一个负责查询,另一个负责修改。

5、ParameterizeMethod(令函数携带参数)

动机:若干函数做了类似的工作,但在函数本体中却包含了不同的值。

做法:建立单一函数,以参数表达那些不同的值。

代码1

voidtenPercentRaise(){

salary*=1.1;

}

voidfivePercentRaise(){

salary*=1.05;

}

代码2:上述代码可以替换如下

voidraise(doublefactor){

salary*=(1+factor);

}

6、ReplaceParameterwithExplicitMethods(以明确函数取代参数)

代码1

staticfinalintENGINEER=0;

staticfinalintSALESMAN=1;

staticfinalintMANAGER=2;

staticEmployeecreate(inttype){

switch(type){

caseENGINEER:

returnnewEngineer();

}

caseENGINEER:

returnnewSalesman();

}

caseENGINEER:

returnnewManager();

}

default:

thrownewIllegalArgumentException("Incorrecttypecodevalue");

}

代码2

staticEmployeecreateEngineer(){

returnnewEngineer();

}

staticEmployeecreateSalesman(){

returnnewSalesman();

}

staticEmployeecreateManager(){

returnnewManager();

}

7、PreserveWholeObject(保持对象完整)

动机:你从某个对象中取出若干值,将它们作为某一次函数调用时的参数。

做法:改为传递整个对象。

代码1intlow=daysTempRange().getLow();

inthigh=daysTempRange().getHigh();

withinPlan=plan.withinRange(low,high);

代码2withinPlan=plan.withinRange(daysTempRange());

8、ReplaceParameterWithMethods(以函数取代参数)

动机:对象调用某个函数,并将所得结果作为参数,传递给另一个函数。而接受该参数的函数本身也能够调用前一个函数。

做法:让参数接受者去除该项参数,并直接调用前一个函数。

代码1

intbasePrice=_quantity*_itemPrice;

discountLevel=getDiscountLevel();

doublefinalPrice=discountedPrice(basePrice,discountLevel);

代码2

intbasePrice=_quantity*_itemPrice;

doublefinalPrice=discountedPrice(basePrice);

9、IntroduceParameterObject(引入参数对象)

某些参数总是很自然地同时出现,这时可以以一个对象取代这些参数。价值在于缩短参数列。

做法:新建一个类,用以表现你想替换的一组参数。将这个类设为不可变的。

比如:

privatefinalDate_start;

privatefinalDate_end;

DateRange(Datestart,Dateend){

_start=start;

_end=end;

}

DategetStart(){

return_start;

}

DategetEnd(){

return_end;

}

10、RemoveSettingMethod(移除设值函数)

动机:类中的某个字段应该在对象创建时被设值,然后就不可再改变。

做法:去掉该字段的所有设值函数。

11、HideMethod(隐藏函数)

动机:有一个函数,从来没有被其他任何类用到。应该将这个函数修改为private

12、ReplaceConstructorwithFactoryMethod(以工厂函数取代构造函数)

动机:你希望在创建对象时不仅仅是做简单的构建动作。

范式1:根据整数(实际是类型码)创建对象

classEmployee{

privateint_type;

staticfinalintENGINEER=0;

staticfinalintSALESMAN=1;

staticfinalintMANAGER=2;

Employee(inttype){

_type=type;

}

staticcreate(inttype){

returnnewEmployee(type);

}

staticEmployeecreate(inttype){

switch(type){

caseENGINEER:

returnnewEngineer();

caseSALESMAN:

returnnewSalesman();

caseMANAGER:

returnnewManager();

default:

thrownewIllegalArgumentException("Incorrecttypecodevalue");

}

}

}

调用:Employeeeng=Employee.create(Employee.ENGINEER);

范式2:根据字符串创建子类对象

staticEmployeecreate(Stringname){

try{

return(Employee)Class.forName(name).newInstance();

}catch(Exceptione){

thrownewIllegalArgumentException("Unabletoinstantiate"+name);

}

}

调用:Employee.create(“Engineer”);

范式3:以明确函数创建子类

classPerson...

staticPersoncreateMale(){

returnnewMale();

}

staticPersoncreateFemale(){

returnnewFemale();

}

调用:Personkent=Person.createMale();

13、EncapsulateDowncase(封装向下转型)

动机:某个函数返回的对象,需要调用者执行向下转型

做法:将向下转型动作转移到函数中。

ObjectlastReading(){

returnreadings.lastElement();

}

ReadinglastReading(){

return(Reading)readings.lastElement();

}

14、ReplaceErrorCodewithException(以异常取代错误码)

动机:某个函数返回一个特定的代码,用以表示某种错误情况。

代码1intwithdraw(intamount){

if(amount>_balance){

return-1;

}

else{

_balance-=amount;

return0;

}

}

代码2voidwithdraw(intamount)throwsBalanceException{

if(amount>_balance)thrownewBalanceException();

_balance-=amount;

}

15、ReplaceExceptionwithTest(以测试取代异常)

代码1

doublegetValueForPeriod(intperiodNumber){

try{

return_values[periodNumber];

}catch(ArrayIndexOutofBoundsExceptione){

return0;

}

}

代码2

doublegetValueForPeriod(intperiodNumber){

if(periodNumber>=_values.length)return0;

return_values[periodNumber];

}

代码3

ResourcegetResource(){

try{

result=(Resource)_available.pop();

_allocated.push(result);

returnresult;

}catch(EmptyStackExceptione){

result=newResource();

_allocated.push(result);

returnresult;

}

}

代码4

ResourcegetResource(){

Resourceresult;

if(_available.isEmpty()){

result=newResource();

_allocated.push(reuslt);

returnresult;

}

else{

result=(Resource)_available.pop();

_allocated.push(result);

returnresult;

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值