重构改善既有代码的设计--简化条件表达式

1、DecomposeConditional(分解条件表达式)

动机:你有一个复杂的条件(if-then-else)语句。

做法:从ifthenelse三个段落中分别提炼出独立函数。

代码1

if(date.before(SUMMER_START)||date.after(SUMMER_END))

charge=quantity*_winterRate+_winterServiceCharge;

elsecharge=quantity*_summerRate;

代码2date.beforedate.after在什么时间之前,在什么时间之后

if(notSummer(date))

charge=winterCharge(quantity);

elsecharge=summerCharge(quantity);

privatebooleannotSummer(Datedate){

returndate.before(SUMMER_START)||date.after(SUMMER_END);

}

privatedoublesummerCharge(intquantity){

returnquantity*_summerRate;

}

privatedoublewinterCharge(intquantity){

returnquantity*_winterRate+winterServiceCharge;

}

2、ConsolidateConditionalExpression(合并条件表达式)

代码1

doubledisabilityAmout(){

if(_seniority<2)return0;

if(_monthsDisabled>12)return0;

if(_isPartTime)return0;

}

代码2

doubledisabilityAmout(){

if(isNotEligibleForDisability())return0;

}

booleanisNotEligibleForDisability(){

return((_seniority<2)||(_monthsDisabled>12)||(_isPartTime));

}

3ConsolidateDuplicateConditionalFragments(合并重复的条件片段)

代码1

if(isSpecialDeal()){

total=price*0.95;

send();

}

else{

total=price*0.98;

send();

}

代码2

if(isSpecialDeal())

total=price*0.95;

else

total=price*0.98;

send();

4、RemoveControlFlag(移除控制标记)

做法:以break语句或者return语句取代控制标记。

代码1

voidcheckSeurity(String[]people){

booleanfound=false;

for(inti=0;i<people.length;i++){

if(!found){

if(people[i].equals("Don")){

sendAlert();

found=true;

}

if(people[i].equals("John")){

sendAlert();

found=true;

}

}

}

}

代码2

voidcheckSeurity(String[]people){

booleanfound=false;

for(inti=0;i<people.length;i++){

if(people[i].equals("Don")){

sendAlert();

break;

}

if(people[i].equals("John")){

sendAlert();

break;

}

}

}

代码3

voidcheckSeurity(String[]people){

Stringfound="";

for(inti=0;i<people.length;i++){

if(found.equals("")){

if(people[i].equals("Don")){

sendAlert();

found="Don";

}

if(people[i].equals("John")){

sendAlert();

found="John";

}

}

}

}

代码4

voidcheckSeurity(String[]people){

for(inti=0;i<people.length;i++){

if(people[i].equals("Don")){

sendAlert();

return"Don";

}

if(people[i].equals("John")){

sendAlert();

return"John";

}

}

}

5、ReplaceNestedConditionalwithGuardClauses(以卫语句取代嵌套条件表达式)

动机:函数中的条件逻辑使人难以看清正常的执行路径。

代码1

doublegetPayAmount(){

doubleresult;

if(_isDead)result=deadAmount();

else{

if(_isSeparated)result=separatedAmount();

else{

if(_isRetired)result=retiredAmount();

elseresult=normalPayAmount();

}

}

returnresult;

}

代码2

doublegetPayAmount(){

if(_isDead)returndeadAmount();

if(_isSeparated)returnseparatedAmount();

if(_isRetired)returnretiredAmount();

returnnormalPayAmount();

}

6、ReplaceConditionalwithPolymorphism(以多态取代条件表达式)

动机:你手上有个条件表达式,它根据对象类型的不同而选择不同的行为。

做法:将这个条件表达式的每个分支放进一个子类内的覆写函数中,然后将原始函数声明为抽象函数

代码1

classEmployee..

doublegetSpeed(){

switch(_type){

caseEUROPEAN:

returngetBaseSpeed();

caseAFRICAN:

returngetBaseSpeed()-getLoadFactor()*_numberOfCoconuts;

caseNORWEGIAN_BLUE:

return(_isNailed)?0:getBaseSpeed(_voitage);

}

thrownewRuntimeException("Shouldbeunreachable");

}

代码2

classEmployeeType...

abstractdoublegetSpeed();

classEngineer...

doublegetSpeed(){

returngetBaseSpeed)();

}

classSaleman...

doublegetSpeed(){

returngetBaseSpeed()-getLoadFactor()*_numberOfCoconuts;

}

classManager...

doublegetSpeed(){

return(_isNailed)?0:getBaseSpeed(_voitage);

}

7、IntroduceNullObject(引入Null对象)

动机:你需要再三检查对象是否为Null

代码1if(customer==null)plan=billingPlan.basic();

elseplan=customer.getPlan();

代码2

classNullCustomerextendsCustomer{

publicbooleanisNull(){

returntrue;

}

}

classCustomer..

publicbooleanisNull(){

returnfalse;

}

如果你喜欢,也可以新建一个借口,昭告大家“这里使用了空对象”;

interfaceNullable{

booleanisNull();

}

classCustomerimplementsNullable

我还喜欢加入一个工厂函数,专门用来创建NullCutomer对象。这样一来,用户就不必知道空对象的存在了:

classCustomer...

staticCustomernewNull(){

returnnewNullCustomer();

}

示例:

classSite...

CustomergetCustomer(){

return(_customer==null)?Customer.newNull():_customer;

}

Customercustomer=site.getCustomer();

BillingPlanplan;

if(customer.isNull())plan=BillingPlan.basic();

elseplan=customer.getPlan();

8、IntroduceAssertion(引入断言)

动机:某一段代码需要对程序状态做出某种假设。

做法:以断言明确表现这种假设

代码1doublegetExpenseLimit(){

//shouldhaveeitherexpenselimitorprimaryproject

return(_expenseLimit!=NULL_EXPENSE)?_expenseLimit;

_primaryProject.getMemberExpenseLimit();

}

代码2doublegetExpenseLimit(){

Assert.isTrue(_expenseLimit!=NULL_EXPENSE||_primaryProject!=null);

return(_expenseLimit!=NULL_EXPENSE)?

_expenseLimit:

_primaryProject.getMemberExpenseLimit();

}

断言是一个条件表示,应该总是为真。如果它失败,表示程序员犯了错误,因此断言的失败应该导致一个非受控异常(uncheckedexception)。断言绝对不能被系统的其他部分使用。实际上,程序最后的成品往往将断言统统删除。因此,标记“某些东西是个断言”是很重要的。

断言可以作为交流与调试的铺助。在交流的角度上,断言可以帮助程序阅读者理解代码所做的假设:在调试的角度上,断言可以再距离bug最近的地方抓住它们。

编写一个辅助类(例如Assert类)当然有所帮助,可惜的是断言参数中的任何表达式不论什么情况都一定会被执行一遍。阻止它的唯一方法就是使用类似下面的手法:

doublegetExpenseLimit(){

Assert.isTrue(Assert.ON&&(_expenseLimit!=NULL_EXPENSE||_primaryProject!=null));

return(_expenseLimit!=NULL_EXPENSE)?

_expenseLimit:

_primaryProject.getMemberExpenseLimit();

如果Assert.ON是个常量,编译器就会对它进行检查;如果它等于false,就不再执行条件表达式后半段代码。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值